diff --git a/backend/app/api.py b/backend/app/api.py index 012a1c3..ed900f9 100644 --- a/backend/app/api.py +++ b/backend/app/api.py @@ -107,6 +107,8 @@ def _rows_to_bars(rows) -> list[Bar]: _ADJUST_MODES = ("bfq", "qfq", "hfq") +# MA 全量集合(前端已改为本地计算 MA,后端始终返回此集合以保证缓存一致) +_FULL_MA_SET = (5, 10, 20, 30, 60, 120, 250) def _adjust_bars(bars: list[Bar], factors, from_mode: str, to_mode: str) -> list[Bar]: @@ -814,10 +816,11 @@ async def screener_preview( symbol = plain_code(ts_code) # --- Redis 读缓存:历史窗口(end 翻页)只增不改,最新窗口每日由全市场同步推进; - # 键含 ver:candles 版本号(同步完成后自增,旧缓存全部失效),TTL 兜底(cache.py)--- + # 键含 ver:candles 版本号(同步完成后自增,旧缓存全部失效),TTL 兜底(cache.py) + # 注:ma_periods 不参与缓存键 —— 前端已改为本地计算 MA,后端始终返回全量 MA 集合 cache_key = cache.digest( "preview", ts_code, timeframe, limit, adjust, - end_dt.strftime("%Y-%m-%d") if end_dt else None, ma_periods, zx_periods, + end_dt.strftime("%Y-%m-%d") if end_dt else None, await cache.get_version("candles"), ) cached = await cache.cache_get(f"pv:{cache_key}") @@ -896,7 +899,8 @@ async def screener_preview( kdj = ind.kdj(highs, lows, closes) boll = ind.bollinger(closes) indicators = { - "ma": {f"ma{p}": _series_to_jsonable(ind.ma(closes, p)) for p in ma_periods}, + # MA 始终返回全量集合(前端本地计算 MA,此处仅保留兼容;缓存键不依赖 ma_periods) + "ma": {f"ma{p}": _series_to_jsonable(ind.ma(closes, p)) for p in _FULL_MA_SET}, "macd": { "dif": _series_to_jsonable(macd["macd"]), "dea": _series_to_jsonable(macd["signal"]), diff --git a/backend/app/config.py b/backend/app/config.py index b5e0203..5e64b9d 100644 --- a/backend/app/config.py +++ b/backend/app/config.py @@ -1,10 +1,15 @@ """应用配置(pydantic-settings)。可由 .env / 环境变量覆盖。""" +from pathlib import Path + from pydantic import model_validator from pydantic_settings import BaseSettings, SettingsConfigDict +# 确保 .env 文件总是相对于 config.py 所在目录加载,无论从哪个目录启动 uvicorn +_ENV_FILE = Path(__file__).resolve().parent.parent / ".env" + class Settings(BaseSettings): - model_config = SettingsConfigDict(env_file=".env", extra="ignore") + model_config = SettingsConfigDict(env_file=str(_ENV_FILE) if _ENV_FILE.exists() else ".env", extra="ignore") app_name: str = "Stock Backtest" diff --git a/backend_run.log b/backend_run.log index 211325c..6784f1c 100644 --- a/backend_run.log +++ b/backend_run.log @@ -1,751 +1,6 @@ -INFO: Started server process [35612] -INFO: Waiting for application startup. -INFO: Application startup complete. -INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit) -INFO: 127.0.0.1:61535 - "GET /api/auth/me HTTP/1.1" 401 Unauthorized -INFO: 127.0.0.1:61572 - "POST /api/auth/login HTTP/1.1" 200 OK -INFO: 127.0.0.1:61574 - "GET /api/screener/preview/000001.SZ?limit=3&adjust=bfq HTTP/1.1" 401 Unauthorized -INFO: 127.0.0.1:61576 - "POST /api/auth/login HTTP/1.1" 200 OK -INFO: 127.0.0.1:61578 - "GET /api/screener/preview/000001.SZ?limit=3 HTTP/1.1" 401 Unauthorized -INFO: 127.0.0.1:61605 - "POST /api/auth/login HTTP/1.1" 200 OK -INFO: 127.0.0.1:61608 - "GET /api/screener/preview/000001.SZ?limit=3&adjust=bfq HTTP/1.1" 200 OK -INFO: 127.0.0.1:62165 - "GET /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:62164 - "GET /api/screener/preview/000001.SZ?limit=500&adjust=qfq&timeframe=1M&mas=5%2C10%2C20%2C60 HTTP/1.1" 200 OK -INFO: 127.0.0.1:62194 - "GET /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:62192 - "GET /api/screener/preview/000001.SZ?limit=500&adjust=qfq&timeframe=1M&mas=5%2C10%2C20%2C60 HTTP/1.1" 200 OK -INFO: 127.0.0.1:62479 - "GET /api/screener/preview/000001.SZ?limit=3&adjust=bfq HTTP/1.1" 200 OK -INFO: 127.0.0.1:62512 - "GET /api/screener/preview/000001.SZ?limit=2&adjust=bfq HTTP/1.1" 200 OK -INFO: 127.0.0.1:63470 - "GET /api/screener/preview/000001.SZ?limit=2&adjust=qfq&timeframe=1M HTTP/1.1" 200 OK -INFO: 127.0.0.1:58419 - "GET /api/screener/preview/000001.SZ?limit=2800&adjust=bfq&timeframe=1d HTTP/1.1" 200 OK -INFO: 127.0.0.1:58464 - "GET /api/screener/preview/000001.SZ?limit=4&adjust=bfq&timeframe=1w HTTP/1.1" 200 OK -INFO: 127.0.0.1:58481 - "GET /api/screener/preview/000001.SZ?limit=2800&adjust=bfq&timeframe=1d HTTP/1.1" 200 OK -INFO: 127.0.0.1:58482 - "GET /api/screener/preview/000001.SZ?limit=4&adjust=bfq&timeframe=1w HTTP/1.1" 200 OK -INFO: 127.0.0.1:58776 - "GET /api/auth/me HTTP/1.1" 401 Unauthorized -INFO: 127.0.0.1:58819 - "POST /api/auth/login HTTP/1.1" 200 OK -INFO: 127.0.0.1:58820 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:58838 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:58855 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:58857 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:58867 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:58829 - "GET /api/stocks?limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:58866 - "GET /api/stocks?limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:58883 - "GET /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:58881 - "GET /api/screener/preview/000001.SZ?limit=500&adjust=qfq&timeframe=1M&mas=5%2C10%2C20%2C60 HTTP/1.1" 200 OK -INFO: 127.0.0.1:58985 - "GET /api/screener/preview/000001.SZ?limit=500&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60 HTTP/1.1" 200 OK -INFO: 127.0.0.1:58988 - "PUT /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:58991 - "GET /api/screener/preview/000001.SZ?limit=800&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60&end=2024-07-24 HTTP/1.1" 200 OK -INFO: 127.0.0.1:59694 - "PUT /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:59696 - "PUT /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:59715 - "POST /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:59733 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:59743 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:59750 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:59761 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:59767 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:59774 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:59749 - "GET /api/stocks?limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:59773 - "GET /api/stocks?limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:59815 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:59823 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:59828 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:59827 - "GET /api/stocks?limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:59861 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:59865 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:59874 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:59872 - "GET /api/stocks?limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:59889 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:59898 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:59903 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:59902 - "GET /api/stocks?limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:59992 - "GET /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:59990 - "GET /api/screener/preview/000008.SZ?limit=500&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60 HTTP/1.1" 200 OK -INFO: 127.0.0.1:59998 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60&end=2024-07-17 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60003 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60&end=2024-07-17 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60018 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60&end=2024-07-17 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60455 - "GET /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:60453 - "GET /api/screener/preview/000008.SZ?limit=500&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60458 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60&end=2024-07-17 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60476 - "GET /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:60474 - "GET /api/screener/preview/000008.SZ?limit=500&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60478 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60&end=2024-07-17 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60498 - "GET /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:60497 - "GET /api/screener/preview/000008.SZ?limit=500&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60501 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60&end=2024-07-17 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60513 - "GET /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:60512 - "GET /api/screener/preview/000008.SZ?limit=500&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60515 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60&end=2024-07-17 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60556 - "GET /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:60554 - "GET /api/screener/preview/000008.SZ?limit=500&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60559 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60&end=2024-07-17 HTTP/1.1" 200 OK -INFO: 127.0.0.1:61756 - "GET /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:61755 - "GET /api/screener/preview/000008.SZ?limit=500&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60 HTTP/1.1" 200 OK -INFO: 127.0.0.1:61760 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60&end=2024-07-17 HTTP/1.1" 200 OK -INFO: 127.0.0.1:63160 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60&end=2024-07-17 HTTP/1.1" 200 OK -INFO: 127.0.0.1:63182 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60&end=2024-07-17 HTTP/1.1" 200 OK -INFO: 127.0.0.1:63271 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:63290 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:63292 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:63330 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:63341 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:63349 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:63291 - "GET /api/stocks?limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:63367 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:63377 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:63384 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:63348 - "GET /api/stocks?limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:63380 - "GET /api/stocks?limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:63403 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:63410 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:63413 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:63412 - "GET /api/stocks?limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:49400 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:49399 - "GET /api/stocks?limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:49461 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:49469 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:49479 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:49478 - "GET /api/stocks?limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:51074 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:51097 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:51100 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:51099 - "GET /api/stocks?limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:53759 - "GET /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:53758 - "GET /api/screener/preview/000008.SZ?limit=500&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60 HTTP/1.1" 200 OK -INFO: 127.0.0.1:53768 - "GET /api/screener/preview/000007.SZ?limit=500&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60 HTTP/1.1" 200 OK -INFO: 127.0.0.1:53773 - "GET /api/screener/preview/000007.SZ?limit=800&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60&end=2024-07-24 HTTP/1.1" 200 OK -INFO: 127.0.0.1:53778 - "GET /api/screener/preview/000007.SZ?limit=800&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60&end=2021-03-31 HTTP/1.1" 200 OK -INFO: 127.0.0.1:53785 - "GET /api/screener/preview/000007.SZ?limit=800&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60&end=2016-12-29 HTTP/1.1" 200 OK -INFO: 127.0.0.1:53787 - "GET /api/screener/preview/000007.SZ?limit=800&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60&end=2012-04-10 HTTP/1.1" 200 OK -INFO: 127.0.0.1:53793 - "GET /api/screener/preview/000007.SZ?limit=800&adjust=qfq&timeframe=1d&mas=5%2C10%2C20%2C60&end=2008-10-10 HTTP/1.1" 200 OK -INFO: 127.0.0.1:53832 - "PUT /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:53848 - "GET /api/screener/preview/000007.SZ?limit=500&adjust=qfq&timeframe=1d&mas=5%2C20%2C60 HTTP/1.1" 200 OK -INFO: 127.0.0.1:53859 - "PUT /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:53855 - "GET /api/screener/preview/000007.SZ?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK -INFO: 127.0.0.1:53852 - "GET /api/screener/preview/000007.SZ?limit=500&adjust=qfq&timeframe=1d&mas=60 HTTP/1.1" 200 OK -INFO: 127.0.0.1:53850 - "GET /api/screener/preview/000007.SZ?limit=500&adjust=qfq&timeframe=1d&mas=5%2C60 HTTP/1.1" 200 OK -INFO: 127.0.0.1:53862 - "GET /api/screener/preview/000007.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK -INFO: 127.0.0.1:53868 - "GET /api/screener/preview/000007.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK -INFO: 127.0.0.1:53870 - "PUT /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:53874 - "GET /api/screener/preview/000007.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK -INFO: 127.0.0.1:53882 - "PUT /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:53879 - "GET /api/screener/preview/000007.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK -INFO: 127.0.0.1:53900 - "GET /api/screener/preview/000007.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK -INFO: 127.0.0.1:53908 - "GET /api/screener/preview/000007.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK -INFO: 127.0.0.1:53915 - "GET /api/screener/preview/000007.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK -INFO: 127.0.0.1:53925 - "GET /api/screener/preview/000007.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK -INFO: 127.0.0.1:53931 - "GET /api/screener/preview/000007.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK -INFO: 127.0.0.1:53934 - "GET /api/screener/preview/000007.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK -INFO: 127.0.0.1:53927 - "GET /api/screener/preview/000007.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK -INFO: 127.0.0.1:53948 - "GET /api/screener/preview/000007.SZ?limit=500&adjust=qfq&timeframe=1d&mas=5 HTTP/1.1" 200 OK -INFO: 127.0.0.1:53952 - "PUT /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:53955 - "GET /api/screener/preview/000007.SZ?limit=800&adjust=qfq&timeframe=1d&mas=5&end=2024-07-24 HTTP/1.1" 200 OK -INFO: 127.0.0.1:53941 - "GET /api/screener/preview/000007.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK -INFO: 127.0.0.1:54082 - "PUT /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:54085 - "PUT /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:54214 - "GET /api/screener/preview/000009.SZ?limit=500&adjust=qfq&timeframe=1d&mas=5 HTTP/1.1" 200 OK -INFO: 127.0.0.1:54216 - "GET /api/screener/preview/000009.SZ?limit=800&adjust=qfq&timeframe=1d&mas=5&end=2024-07-24 HTTP/1.1" 200 OK -INFO: 127.0.0.1:54303 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:54301 - "GET /api/stocks?limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:54936 - "GET /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:54933 - "GET /api/screener/preview/000008.SZ?limit=500&adjust=qfq&timeframe=1d&mas=5 HTTP/1.1" 200 OK -INFO: 127.0.0.1:54943 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1d&mas=5&end=2024-07-17 HTTP/1.1" 200 OK -INFO: 127.0.0.1:54950 - "PUT /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:54947 - "GET /api/screener/preview/000008.SZ?limit=500&adjust=qfq&timeframe=1w&mas=5 HTTP/1.1" 200 OK -INFO: 127.0.0.1:54955 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1w&mas=5&end=2016-09-26 HTTP/1.1" 200 OK -INFO: 127.0.0.1:59351 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:59369 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:59372 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:59371 - "GET /api/stocks?limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60036 - "GET /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:60035 - "GET /api/screener/preview/000008.SZ?limit=500&adjust=qfq&timeframe=1w&mas=5 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60042 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1w&mas=5&end=2016-09-26 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60069 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1w&mas=5&end=2000-05-15 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60229 - "GET /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:60228 - "GET /api/screener/preview/000008.SZ?limit=500&adjust=qfq&timeframe=1w&mas=5 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60245 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1w&mas=5&end=2016-09-26 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60392 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1w&mas=5&end=2016-09-26 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60388 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1w&mas=5&end=2016-09-26 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60395 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1w&mas=5&end=2016-09-26 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60399 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1w&mas=5&end=2016-09-26 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60407 - "PUT /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:60404 - "GET /api/screener/preview/000008.SZ?limit=500&adjust=qfq&timeframe=1w&mas=5%2C10 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60412 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1w&mas=5%2C10&end=2016-09-26 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60416 - "GET /api/screener/preview/000008.SZ?limit=500&adjust=qfq&timeframe=1w&mas=5%2C10%2C20 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60419 - "PUT /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:60423 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1w&mas=5%2C10%2C20&end=2016-09-26 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60537 - "GET /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:60536 - "GET /api/screener/preview/000008.SZ?limit=500&adjust=qfq&timeframe=1w&mas=5%2C10%2C20 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60544 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1w&mas=5%2C10%2C20&end=2016-09-26 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60691 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1w&mas=5%2C10%2C20&end=2016-09-26 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60702 - "PUT /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:60699 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1w&mas=5%2C10%2C20&end=2016-09-26 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60695 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1w&mas=5%2C10%2C20&end=2016-09-26 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60713 - "GET /api/screener/preview/000008.SZ?limit=800&adjust=qfq&timeframe=1w&mas=5%2C10%2C20&end=2016-09-26 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60722 - "GET /api/screener/preview/000002.SZ?limit=500&adjust=qfq&timeframe=1w&mas=5%2C10%2C20 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60730 - "GET /api/screener/preview/000002.SZ?limit=800&adjust=qfq&timeframe=1w&mas=5%2C10%2C20&end=2016-12-26 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60763 - "GET /api/screener/preview/000002.SZ?limit=800&adjust=qfq&timeframe=1w&mas=5%2C10%2C20&end=2000-11-13 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60775 - "DELETE /api/watchlist/000008.SZ HTTP/1.1" 200 OK -INFO: 127.0.0.1:60778 - "POST /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:60783 - "DELETE /api/watchlist/000008.SZ HTTP/1.1" 200 OK -INFO: 127.0.0.1:60797 - "GET /api/screener/sync/status HTTP/1.1" 200 OK -INFO: 127.0.0.1:60898 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:60907 - "GET /api/screener/sync/status HTTP/1.1" 200 OK -INFO: 127.0.0.1:60916 - "GET /api/screener/queries?limit=20 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60897 - "GET /api/stocks?limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60914 - "POST /api/screener/run HTTP/1.1" 200 OK -INFO: 127.0.0.1:60972 - "GET /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:60971 - "GET /api/screener/preview/600529.SH?limit=500&adjust=qfq&timeframe=1w&mas=5%2C10%2C20 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60988 - "GET /api/screener/preview/600529.SH?limit=800&adjust=qfq&timeframe=1w&mas=5%2C10%2C20&end=2016-12-26 HTTP/1.1" 200 OK -INFO: 127.0.0.1:61042 - "PUT /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:61032 - "GET /api/screener/preview/600529.SH?limit=500&adjust=qfq&timeframe=1w&mas=10%2C20 HTTP/1.1" 200 OK -INFO: 127.0.0.1:61034 - "GET /api/screener/preview/600529.SH?limit=500&adjust=qfq&timeframe=1w&mas=20 HTTP/1.1" 200 OK -INFO: 127.0.0.1:61036 - "GET /api/screener/preview/600529.SH?limit=500&adjust=qfq&timeframe=1w HTTP/1.1" 200 OK -INFO: 127.0.0.1:61048 - "GET /api/screener/preview/600529.SH?limit=800&adjust=qfq&timeframe=1w&end=2016-12-26 HTTP/1.1" 200 OK -INFO: 127.0.0.1:61056 - "GET /api/screener/preview/600529.SH?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK -INFO: 127.0.0.1:61059 - "PUT /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:61063 - "GET /api/screener/preview/600529.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK -INFO: 127.0.0.1:61075 - "PUT /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:61078 - "PUT /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:61082 - "PUT /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:61106 - "PUT /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:61165 - "GET /api/screener/preview/002668.SZ?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK -INFO: 127.0.0.1:61169 - "GET /api/screener/preview/002668.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK -INFO: 127.0.0.1:62065 - "GET /api/screener/preview/002668.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK -INFO: 127.0.0.1:62308 - "GET /api/screener/preview/002668.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 500 Internal Server Error -ERROR: Exception in ASGI application -Traceback (most recent call last): - File "D:\Project\stock\backend\.venv\Lib\site-packages\uvicorn\protocols\http\httptools_impl.py", line 422, in run_asgi - result = await app( # type: ignore[func-returns-value] - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - self.scope, self.receive, self.send - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ) - ^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\uvicorn\middleware\proxy_headers.py", line 63, in __call__ - return await self.app(scope, receive, send) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\fastapi\applications.py", line 1163, in __call__ - await super().__call__(scope, receive, send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\starlette\applications.py", line 90, in __call__ - await self.middleware_stack(scope, receive, send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\starlette\middleware\errors.py", line 186, in __call__ - raise exc - File "D:\Project\stock\backend\.venv\Lib\site-packages\starlette\middleware\errors.py", line 164, in __call__ - await self.app(scope, receive, _send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\starlette\middleware\cors.py", line 88, in __call__ - await self.app(scope, receive, send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\starlette\middleware\exceptions.py", line 63, in __call__ - await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app - raise exc - File "D:\Project\stock\backend\.venv\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app - await app(scope, receive, sender) - File "D:\Project\stock\backend\.venv\Lib\site-packages\fastapi\middleware\asyncexitstack.py", line 18, in __call__ - await self.app(scope, receive, send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\starlette\routing.py", line 660, in __call__ - await self.middleware_stack(scope, receive, send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\fastapi\routing.py", line 2734, in app - await route.handle(scope, receive, send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\fastapi\routing.py", line 1780, in handle - await self.original_router.handle(scope, receive, send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\fastapi\routing.py", line 2789, in handle - await included_router._handle_selected(scope, receive, send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\fastapi\routing.py", line 1800, in _handle_selected - await original_route.handle(scope, receive, send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\fastapi\routing.py", line 1279, in handle - await app(scope, receive, send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\fastapi\routing.py", line 158, in app - await wrap_app_handling_exceptions(app, request)(scope, receive, send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app - raise exc - File "D:\Project\stock\backend\.venv\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app - await app(scope, receive, sender) - File "D:\Project\stock\backend\.venv\Lib\site-packages\fastapi\routing.py", line 144, in app - response = await f(request) - ^^^^^^^^^^^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\fastapi\routing.py", line 481, in app - solved_result = await solve_dependencies( - ^^^^^^^^^^^^^^^^^^^^^^^^^ - ...<6 lines>... - ) - ^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\fastapi\dependencies\utils.py", line 674, in solve_dependencies - solved = await call(**solved_result.values) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "D:\Project\stock\backend\app\auth.py", line 102, in require_user - auth_session = await get_auth_session(stock_session, db) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "D:\Project\stock\backend\app\auth.py", line 85, in get_auth_session - auth_session = (await db.execute(stmt)).scalar_one_or_none() - ^^^^^^^^^^^^^^^^^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\ext\asyncio\session.py", line 448, in execute - result = await greenlet_spawn( - ^^^^^^^^^^^^^^^^^^^^^ - ...<6 lines>... - ) - ^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 201, in greenlet_spawn - result = context.throw(*sys.exc_info()) - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2373, in execute - return self._execute_internal( - ~~~~~~~~~~~~~~~~~~~~~~^ - statement, - ^^^^^^^^^^ - ...<4 lines>... - _add_event=_add_event, - ^^^^^^^^^^^^^^^^^^^^^^ - ) - ^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2261, in _execute_internal - conn = self._connection_for_bind(bind) - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2113, in _connection_for_bind - return trans._connection_for_bind(engine, execution_options) - ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "", line 2, in _connection_for_bind - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\orm\state_changes.py", line 137, in _go - ret_value = fn(self, *arg, **kw) - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 1191, in _connection_for_bind - conn = bind.connect() - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3295, in connect - return self._connection_cls(self) - ~~~~~~~~~~~~~~~~~~~~^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 144, in __init__ - self._dbapi_connection = engine.raw_connection() - ~~~~~~~~~~~~~~~~~~~~~^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3319, in raw_connection - return self.pool.connect() - ~~~~~~~~~~~~~~~~~^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 448, in connect - return _ConnectionFairy._checkout(self) - ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 1272, in _checkout - fairy = _ConnectionRecord.checkout(pool) - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 717, in checkout - with util.safe_reraise(): - ~~~~~~~~~~~~~~~~~^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__ - raise exc_value.with_traceback(exc_tb) - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 715, in checkout - dbapi_connection = rec.get_connection() - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 866, in get_connection - self.__connect() - ~~~~~~~~~~~~~~^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 900, in __connect - with util.safe_reraise(): - ~~~~~~~~~~~~~~~~~^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__ - raise exc_value.with_traceback(exc_tb) - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 896, in __connect - self.dbapi_connection = connection = pool._invoke_creator(self) - ~~~~~~~~~~~~~~~~~~~~^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\engine\create.py", line 667, in connect - return dialect.connect(*cargs_tup, **cparams) - ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\engine\default.py", line 630, in connect - return self.loaded_dbapi.connect(*cargs, **cparams) # type: ignore[no-any-return] # NOQA: E501 - ~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\dialects\postgresql\asyncpg.py", line 955, in connect - await_only(creator_fn(*arg, **kw)), - ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 132, in await_only - return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 - ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 196, in greenlet_spawn - value = await result - ^^^^^^^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\asyncpg\connection.py", line 2443, in connect - return await connect_utils._connect( - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ...<22 lines>... - ) - ^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\asyncpg\connect_utils.py", line 1249, in _connect - raise last_error or exceptions.TargetServerAttributeNotMatched( - ...<2 lines>... - ) - File "D:\Project\stock\backend\.venv\Lib\site-packages\asyncpg\connect_utils.py", line 1218, in _connect - conn = await _connect_addr( - ^^^^^^^^^^^^^^^^^^^^ - ...<6 lines>... - ) - ^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\asyncpg\connect_utils.py", line 1054, in _connect_addr - return await __connect_addr(params, True, *args) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\asyncpg\connect_utils.py", line 1099, in __connect_addr - tr, pr = await connector - ^^^^^^^^^^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\asyncpg\connect_utils.py", line 969, in _create_ssl_connection - tr, pr = await loop.create_connection( - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ...<2 lines>... - host, port) - ^^^^^^^^^^^ - File "C:\Users\cirry\scoop\apps\python\current\Lib\asyncio\base_events.py", line 1168, in create_connection - raise exceptions[0] - File "C:\Users\cirry\scoop\apps\python\current\Lib\asyncio\base_events.py", line 1143, in create_connection - sock = await self._connect_sock( - ^^^^^^^^^^^^^^^^^^^^^^^^^ - exceptions, addrinfo, laddr_infos) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "C:\Users\cirry\scoop\apps\python\current\Lib\asyncio\base_events.py", line 1042, in _connect_sock - await self.sock_connect(sock, address) - File "C:\Users\cirry\scoop\apps\python\current\Lib\asyncio\proactor_events.py", line 728, in sock_connect - return await self._proactor.connect(sock, address) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "C:\Users\cirry\scoop\apps\python\current\Lib\asyncio\windows_events.py", line 804, in _poll - value = callback(transferred, key, ov) - File "C:\Users\cirry\scoop\apps\python\current\Lib\asyncio\windows_events.py", line 600, in finish_connect - ov.getresult() - ~~~~~~~~~~~~^^ -ConnectionRefusedError: [WinError 1225] Զ̼ܾӡ -INFO: 127.0.0.1:62317 - "GET /api/screener/preview/002668.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 500 Internal Server Error -ERROR: Exception in ASGI application -Traceback (most recent call last): - File "D:\Project\stock\backend\.venv\Lib\site-packages\uvicorn\protocols\http\httptools_impl.py", line 422, in run_asgi - result = await app( # type: ignore[func-returns-value] - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - self.scope, self.receive, self.send - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ) - ^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\uvicorn\middleware\proxy_headers.py", line 63, in __call__ - return await self.app(scope, receive, send) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\fastapi\applications.py", line 1163, in __call__ - await super().__call__(scope, receive, send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\starlette\applications.py", line 90, in __call__ - await self.middleware_stack(scope, receive, send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\starlette\middleware\errors.py", line 186, in __call__ - raise exc - File "D:\Project\stock\backend\.venv\Lib\site-packages\starlette\middleware\errors.py", line 164, in __call__ - await self.app(scope, receive, _send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\starlette\middleware\cors.py", line 88, in __call__ - await self.app(scope, receive, send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\starlette\middleware\exceptions.py", line 63, in __call__ - await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app - raise exc - File "D:\Project\stock\backend\.venv\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app - await app(scope, receive, sender) - File "D:\Project\stock\backend\.venv\Lib\site-packages\fastapi\middleware\asyncexitstack.py", line 18, in __call__ - await self.app(scope, receive, send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\starlette\routing.py", line 660, in __call__ - await self.middleware_stack(scope, receive, send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\fastapi\routing.py", line 2734, in app - await route.handle(scope, receive, send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\fastapi\routing.py", line 1780, in handle - await self.original_router.handle(scope, receive, send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\fastapi\routing.py", line 2789, in handle - await included_router._handle_selected(scope, receive, send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\fastapi\routing.py", line 1800, in _handle_selected - await original_route.handle(scope, receive, send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\fastapi\routing.py", line 1279, in handle - await app(scope, receive, send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\fastapi\routing.py", line 158, in app - await wrap_app_handling_exceptions(app, request)(scope, receive, send) - File "D:\Project\stock\backend\.venv\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app - raise exc - File "D:\Project\stock\backend\.venv\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app - await app(scope, receive, sender) - File "D:\Project\stock\backend\.venv\Lib\site-packages\fastapi\routing.py", line 144, in app - response = await f(request) - ^^^^^^^^^^^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\fastapi\routing.py", line 481, in app - solved_result = await solve_dependencies( - ^^^^^^^^^^^^^^^^^^^^^^^^^ - ...<6 lines>... - ) - ^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\fastapi\dependencies\utils.py", line 674, in solve_dependencies - solved = await call(**solved_result.values) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "D:\Project\stock\backend\app\auth.py", line 102, in require_user - auth_session = await get_auth_session(stock_session, db) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "D:\Project\stock\backend\app\auth.py", line 85, in get_auth_session - auth_session = (await db.execute(stmt)).scalar_one_or_none() - ^^^^^^^^^^^^^^^^^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\ext\asyncio\session.py", line 448, in execute - result = await greenlet_spawn( - ^^^^^^^^^^^^^^^^^^^^^ - ...<6 lines>... - ) - ^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 201, in greenlet_spawn - result = context.throw(*sys.exc_info()) - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2373, in execute - return self._execute_internal( - ~~~~~~~~~~~~~~~~~~~~~~^ - statement, - ^^^^^^^^^^ - ...<4 lines>... - _add_event=_add_event, - ^^^^^^^^^^^^^^^^^^^^^^ - ) - ^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2261, in _execute_internal - conn = self._connection_for_bind(bind) - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 2113, in _connection_for_bind - return trans._connection_for_bind(engine, execution_options) - ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "", line 2, in _connection_for_bind - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\orm\state_changes.py", line 137, in _go - ret_value = fn(self, *arg, **kw) - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\orm\session.py", line 1191, in _connection_for_bind - conn = bind.connect() - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3295, in connect - return self._connection_cls(self) - ~~~~~~~~~~~~~~~~~~~~^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 144, in __init__ - self._dbapi_connection = engine.raw_connection() - ~~~~~~~~~~~~~~~~~~~~~^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3319, in raw_connection - return self.pool.connect() - ~~~~~~~~~~~~~~~~~^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 448, in connect - return _ConnectionFairy._checkout(self) - ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 1272, in _checkout - fairy = _ConnectionRecord.checkout(pool) - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 717, in checkout - with util.safe_reraise(): - ~~~~~~~~~~~~~~~~~^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__ - raise exc_value.with_traceback(exc_tb) - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 715, in checkout - dbapi_connection = rec.get_connection() - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 866, in get_connection - self.__connect() - ~~~~~~~~~~~~~~^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 900, in __connect - with util.safe_reraise(): - ~~~~~~~~~~~~~~~~~^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 122, in __exit__ - raise exc_value.with_traceback(exc_tb) - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 896, in __connect - self.dbapi_connection = connection = pool._invoke_creator(self) - ~~~~~~~~~~~~~~~~~~~~^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\engine\create.py", line 667, in connect - return dialect.connect(*cargs_tup, **cparams) - ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\engine\default.py", line 630, in connect - return self.loaded_dbapi.connect(*cargs, **cparams) # type: ignore[no-any-return] # NOQA: E501 - ~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\dialects\postgresql\asyncpg.py", line 955, in connect - await_only(creator_fn(*arg, **kw)), - ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 132, in await_only - return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501 - ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 196, in greenlet_spawn - value = await result - ^^^^^^^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\asyncpg\connection.py", line 2443, in connect - return await connect_utils._connect( - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ...<22 lines>... - ) - ^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\asyncpg\connect_utils.py", line 1249, in _connect - raise last_error or exceptions.TargetServerAttributeNotMatched( - ...<2 lines>... - ) - File "D:\Project\stock\backend\.venv\Lib\site-packages\asyncpg\connect_utils.py", line 1218, in _connect - conn = await _connect_addr( - ^^^^^^^^^^^^^^^^^^^^ - ...<6 lines>... - ) - ^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\asyncpg\connect_utils.py", line 1054, in _connect_addr - return await __connect_addr(params, True, *args) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\asyncpg\connect_utils.py", line 1099, in __connect_addr - tr, pr = await connector - ^^^^^^^^^^^^^^^ - File "D:\Project\stock\backend\.venv\Lib\site-packages\asyncpg\connect_utils.py", line 969, in _create_ssl_connection - tr, pr = await loop.create_connection( - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ...<2 lines>... - host, port) - ^^^^^^^^^^^ - File "C:\Users\cirry\scoop\apps\python\current\Lib\asyncio\base_events.py", line 1168, in create_connection - raise exceptions[0] - File "C:\Users\cirry\scoop\apps\python\current\Lib\asyncio\base_events.py", line 1143, in create_connection - sock = await self._connect_sock( - ^^^^^^^^^^^^^^^^^^^^^^^^^ - exceptions, addrinfo, laddr_infos) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "C:\Users\cirry\scoop\apps\python\current\Lib\asyncio\base_events.py", line 1042, in _connect_sock - await self.sock_connect(sock, address) - File "C:\Users\cirry\scoop\apps\python\current\Lib\asyncio\proactor_events.py", line 728, in sock_connect - return await self._proactor.connect(sock, address) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "C:\Users\cirry\scoop\apps\python\current\Lib\asyncio\windows_events.py", line 804, in _poll - value = callback(transferred, key, ov) - File "C:\Users\cirry\scoop\apps\python\current\Lib\asyncio\windows_events.py", line 600, in finish_connect - ov.getresult() - ~~~~~~~~~~~~^^ -ConnectionRefusedError: [WinError 1225] Զ̼ܾӡ -INFO: 127.0.0.1:62379 - "GET /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:62378 - "GET /api/screener/preview/600529.SH?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK -INFO: 127.0.0.1:62397 - "GET /api/screener/preview/600529.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK -INFO: 127.0.0.1:62416 - "GET /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:62425 - "GET /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:62423 - "GET /api/screener/preview/600529.SH?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK -INFO: 127.0.0.1:62433 - "GET /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:62415 - "GET /api/screener/preview/600529.SH?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK -INFO: 127.0.0.1:62429 - "GET /api/screener/preview/600529.SH?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK -INFO: 127.0.0.1:62437 - "GET /api/screener/preview/600529.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK -INFO: 127.0.0.1:63003 - "GET /api/screener/preview/600529.SH?limit=500&adjust=qfq&timeframe=1d&end=2018-10-29 HTTP/1.1" 200 OK -INFO: 127.0.0.1:63007 - "GET /api/screener/preview/600529.SH?limit=800&adjust=qfq&timeframe=1d&end=2016-10-12 HTTP/1.1" 200 OK -INFO: 127.0.0.1:63659 - "GET /api/screener/preview/600529.SH?limit=800&adjust=qfq&timeframe=1d&end=2016-10-12 HTTP/1.1" 200 OK -INFO: 127.0.0.1:63684 - "GET /api/screener/preview/600529.SH?limit=800&adjust=qfq&timeframe=1d&end=2016-10-12 HTTP/1.1" 200 OK -INFO: 127.0.0.1:63711 - "GET /api/screener/preview/600529.SH?limit=800&adjust=qfq&timeframe=1d&end=2016-10-12 HTTP/1.1" 200 OK -INFO: 127.0.0.1:63732 - "GET /api/screener/preview/600529.SH?limit=800&adjust=qfq&timeframe=1d&end=2016-10-12 HTTP/1.1" 200 OK -INFO: 127.0.0.1:63759 - "GET /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:63757 - "GET /api/screener/preview/600529.SH?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK -INFO: 127.0.0.1:63765 - "GET /api/screener/preview/600529.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK -INFO: 127.0.0.1:56553 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:56569 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:56572 - "GET /api/screener/sync/status HTTP/1.1" 200 OK -INFO: 127.0.0.1:56582 - "GET /api/screener/queries?limit=20 HTTP/1.1" 200 OK -INFO: 127.0.0.1:56581 - "POST /api/screener/run HTTP/1.1" 200 OK -INFO: 127.0.0.1:56608 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:56617 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:56623 - "GET /api/screener/sync/status HTTP/1.1" 200 OK -INFO: 127.0.0.1:56628 - "GET /api/screener/queries?limit=20 HTTP/1.1" 200 OK -INFO: 127.0.0.1:56627 - "POST /api/screener/run HTTP/1.1" 200 OK -INFO: 127.0.0.1:56694 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:56691 - "GET /api/stocks?limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:56732 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:56744 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:56747 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:56746 - "GET /api/stocks?limit=100&offset=0 HTTP/1.1" 200 OK -==== restart 2026-08-15 23:03:42 ==== -INFO: Will watch for changes in these directories: ['D:\\Project\\stock\\backend'] -INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit) -INFO: Started reloader process [17652] using WatchFiles -INFO: Started server process [23704] -INFO: Waiting for application startup. -INFO: Application startup complete. -INFO: 127.0.0.1:61442 - "POST /api/auth/login HTTP/1.1" 200 OK -INFO: 127.0.0.1:61447 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:61456 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:61453 - "GET /api/stocks?limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:61543 - "GET /api/stocks?limit=1 HTTP/1.1" 401 Unauthorized -INFO: 127.0.0.1:61544 - "GET /api/stocks?limit=1 HTTP/1.1" 401 Unauthorized -WARNING: WatchFiles detected changes in 'app\api.py'. Reloading... - INFO: 127.0.0.1:65392 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:65410 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:65413 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:65412 - "GET /api/stocks?limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:65424 - "GET /api/stocks?limit=3 HTTP/1.1" 200 OK -==== restart 2026-08-15 23:37:04 ==== -INFO: Will watch for changes in these directories: ['D:\\Project\\stock\\backend'] -INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit) -INFO: Started reloader process [48108] using WatchFiles -INFO: Started server process [47480] -INFO: Waiting for application startup. -INFO: Application startup complete. -INFO: 127.0.0.1:49363 - "GET /api/stocks?limit=3 HTTP/1.1" 200 OK -WARNING: WatchFiles detected changes in 'app\api.py'. Reloading... - ==== restart 2026-08-15 23:46:54 ==== -error: Failed to spawn: `uvicorn` - Caused by: program not found -INFO: Will watch for changes in these directories: ['D:\\Project\\stock\\backend'] -INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit) -INFO: Started reloader process [42580] using WatchFiles -INFO: Started server process [46816] -INFO: Waiting for application startup. -INFO: Application startup complete. -INFO: 127.0.0.1:50670 - "GET /api/stocks?limit=1 HTTP/1.1" 401 Unauthorized -INFO: 127.0.0.1:50683 - "GET /api/stocks?limit=3&sort=total_mv&order=desc HTTP/1.1" 200 OK -INFO: 127.0.0.1:50686 - "GET /api/stocks?limit=3&sort=turnover_rate&order=desc HTTP/1.1" 200 OK -INFO: 127.0.0.1:50687 - "GET /api/stocks?limit=3&sort=pe_ttm&order=asc HTTP/1.1" 200 OK -INFO: 127.0.0.1:50688 - "GET /api/stocks?limit=3& HTTP/1.1" 200 OK -INFO: 127.0.0.1:51208 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:51217 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:51224 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:51223 - "GET /api/stocks?sort=symbol&order=asc&limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:51230 - "GET /api/stocks?sort=pe_ttm&order=desc&limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:51231 - "GET /api/stocks?sort=pe_ttm&order=asc&limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:51241 - "GET /api/stocks?sort=pe_ttm&order=desc&limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:51243 - "GET /api/stocks?sort=pe_ttm&order=asc&limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:51248 - "GET /api/stocks?sort=total_mv&order=desc&limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:51265 - "GET /api/stocks?sort=turnover_rate&order=desc&limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:51273 - "GET /api/stocks?sort=total_mv&order=desc&limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:51315 - "GET /api/trades?ts_code=688825.SH HTTP/1.1" 200 OK -INFO: 127.0.0.1:51320 - "GET /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:51319 - "GET /api/screener/preview/688825.SH?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK -INFO: 127.0.0.1:51368 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:51375 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:51384 - "GET /api/stocks?sort=symbol&order=asc&limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:51385 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:51845 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:51843 - "GET /api/stocks?sort=symbol&order=asc&limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:51958 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:51957 - "GET /api/stocks?sort=symbol&order=asc&limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:52092 - "GET /api/stocks?sort=symbol&order=asc&limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:52094 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:52455 - "GET /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:52453 - "GET /api/trades?ts_code=000001.SZ HTTP/1.1" 200 OK -INFO: 127.0.0.1:52454 - "GET /api/screener/preview/000001.SZ?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK -INFO: 127.0.0.1:52465 - "GET /api/screener/preview/000001.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK -WARNING: WatchFiles detected changes in 'app\data\market_overview.py'. Reloading... - INFO: 127.0.0.1:53348 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:53466 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:53593 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:53600 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:53614 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:53616 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:53772 - "GET /api/market/overview HTTP/1.1" 404 Not Found -INFO: 127.0.0.1:54143 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:54156 - "GET /api/market/overview HTTP/1.1" 404 Not Found -INFO: 127.0.0.1:54155 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:54160 - "GET /api/market/overview HTTP/1.1" 404 Not Found -INFO: 127.0.0.1:54166 - "GET /api/market/overview HTTP/1.1" 404 Not Found -INFO: 127.0.0.1:54952 - "GET /api/market/overview HTTP/1.1" 404 Not Found -INFO: 127.0.0.1:55237 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:55254 - "GET /api/market/overview HTTP/1.1" 404 Not Found -INFO: 127.0.0.1:55252 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:55259 - "GET /api/market/overview HTTP/1.1" 404 Not Found -INFO: 127.0.0.1:55269 - "GET /api/screener/sync/status HTTP/1.1" 200 OK -INFO: 127.0.0.1:55280 - "GET /api/market/overview HTTP/1.1" 404 Not Found -INFO: 127.0.0.1:55282 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:55281 - "GET /api/stocks?sort=symbol&order=asc&limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:55286 - "GET /api/stocks?sort=circ_mv&order=desc&limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:55294 - "GET /api/stocks?sort=total_mv&order=desc&limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:55318 - "GET /api/trades?ts_code=603259.SH HTTP/1.1" 200 OK -INFO: 127.0.0.1:55320 - "GET /api/watchlist HTTP/1.1" 200 OK -INFO: 127.0.0.1:55319 - "GET /api/screener/preview/603259.SH?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK -INFO: 127.0.0.1:55330 - "GET /api/screener/preview/603259.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK -INFO: 127.0.0.1:55349 - "GET /api/screener/preview/603259.SH?limit=800&adjust=qfq&timeframe=1d&end=2021-04-07 HTTP/1.1" 200 OK -INFO: 127.0.0.1:55433 - "GET /api/stocks?sort=total_mv&order=desc&limit=100&offset=100 HTTP/1.1" 200 OK -INFO: 127.0.0.1:56175 - "GET /api/market/overview HTTP/1.1" 404 Not Found -INFO: 127.0.0.1:56189 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:56208 - "GET /api/market/overview HTTP/1.1" 404 Not Found -INFO: 127.0.0.1:56204 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:56279 - "GET /api/market/overview HTTP/1.1" 404 Not Found -INFO: 127.0.0.1:56281 - "GET /api/market/overview HTTP/1.1" 404 Not Found -INFO: 127.0.0.1:56621 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:56638 - "GET /api/market/overview HTTP/1.1" 404 Not Found -INFO: 127.0.0.1:56637 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:56644 - "GET /api/market/overview HTTP/1.1" 404 Not Found -==== restart 2026-08-16 20:03:31 ==== INFO: Will watch for changes in these directories: ['D:\\Project\\stock\\backend'] INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -INFO: Started reloader process [37952] using WatchFiles -INFO: Started server process [45584] +INFO: Started reloader process [40700] using WatchFiles +INFO: Started server process [42044] INFO: Waiting for application startup. INFO: Application startup complete. -INFO: 127.0.0.1:59228 - "GET /api/health HTTP/1.1" 200 OK -INFO: 127.0.0.1:59686 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:59399 - "GET /api/auth/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:59722 - "GET /api/preferences HTTP/1.1" 200 OK -INFO: 127.0.0.1:59723 - "POST /api/auth/login HTTP/1.1" 200 OK -INFO: 127.0.0.1:59725 - "GET /api/stocks/facets HTTP/1.1" 200 OK -INFO: 127.0.0.1:59724 - "GET /api/stocks?sort=symbol&order=asc&limit=100&offset=0 HTTP/1.1" 200 OK -INFO: 127.0.0.1:59733 - "GET /api/trades?ts_code=000006.SZ HTTP/1.1" 200 OK -INFO: 127.0.0.1:59736 - "GET /api/watchlist HTTP/1.1" 200 OK -WARNING: WatchFiles detected changes in 'debug_gaps.py', 'debug_counts.py', 'debug_future.py', 'debug_preview.py', 'debug_live.py', 'debug_md.py'. Reloading... - \ No newline at end of file diff --git a/frontend/src/components/DetailKLine.vue b/frontend/src/components/DetailKLine.vue index d8c3a0a..0393221 100644 --- a/frontend/src/components/DetailKLine.vue +++ b/frontend/src/components/DetailKLine.vue @@ -129,7 +129,22 @@ const g = (k: string) => (ts: number) => { }; // 动态 MA:按周期组合注册一次(figures 的 key 必须静态,故按签名建缓存) +// 前端直接从收盘价计算 MA,无需后端重拉数据,切换均线周期即时响应 const _maReg = new Set(); + +/** 滚动均值:O(n) 滑动窗口,min_periods=1(与后端 pandas rolling 行为一致) */ +function computeMA(closes: number[], period: number): (number | null)[] { + const n = closes.length; + const result: (number | null)[] = new Array(n); + let sum = 0; + for (let i = 0; i < n; i++) { + sum += closes[i]; + if (i >= period) sum -= closes[i - period]; + result[i] = sum / Math.min(i + 1, period); + } + return result; +} + function ensureMaIndicator(periods: number[]) { const sig = [...periods].sort((a, b) => a - b).join('_'); if (_maReg.has(sig)) return `pv-ma-${sig}`; @@ -140,11 +155,20 @@ function ensureMaIndicator(periods: number[]) { key: `ma${p}`, title: `MA${p}`, type: 'line', styles: () => ({ color: MA_COLORS[i % MA_COLORS.length] }), })), - calc: (d: KLineData[]) => d.map((bar) => { - const row: Record = {}; - for (const p of periods) row[`ma${p}`] = g(`ma${p}`)(bar.timestamp); - return row; - }), + calc: (d: KLineData[]) => { + // 前端直接按收盘价计算 MA,不从后端 PV 读取 + const closes = d.map((b) => b.close); + const maValues: Record = {}; + for (const p of periods) maValues[`ma${p}`] = computeMA(closes, p); + return d.map((_, i) => { + const row: Record = {}; + for (const p of periods) { + const v = maValues[`ma${p}`][i]; + if (v != null) row[`ma${p}`] = v; + } + return row; + }); + }, }); _maReg.add(sig); return `pv-ma-${sig}`; diff --git a/frontend/src/components/StockDetailOverlay.vue b/frontend/src/components/StockDetailOverlay.vue index d8ff162..27f0c6a 100644 --- a/frontend/src/components/StockDetailOverlay.vue +++ b/frontend/src/components/StockDetailOverlay.vue @@ -385,8 +385,7 @@ watch(active, (code) => { }, { immediate: true }); watch(adjust, () => load(active.value)); watch(timeframe, () => load(active.value)); -// MA 周期变化也要重拉(后端按 mas 计算指标序列) -watch(maPeriods, () => load(active.value)); +// MA 周期变化:前端直接从收盘价计算,无需重拉后端数据(DetailKLine.vue 的 watch 会触发图表重建) // 切股时同步自选状态 watch(active, (code) => {