From 7369358d08d5a212fb46d96e831d93174f551148 Mon Sep 17 00:00:00 2001 From: shy3130 <415333856@qq.com> Date: Thu, 18 Jun 2026 17:18:23 +0800 Subject: [PATCH] Initial release v0.1.19 --- .env.example | 18 + .gitignore | 86 + Dockerfile | 31 + LICENSE | 21 + README.md | 304 ++ VERSION | 1 + backend/app/__init__.py | 3 + backend/app/api/__init__.py | 1 + backend/app/api/analysis.py | 204 ++ backend/app/api/backtest.py | 461 +++ backend/app/api/data.py | 710 +++++ backend/app/api/ext_data.py | 825 ++++++ backend/app/api/financials.py | 120 + backend/app/api/indices.py | 149 + backend/app/api/intraday.py | 183 ++ backend/app/api/kline.py | 716 +++++ backend/app/api/overview.py | 540 ++++ backend/app/api/pipeline.py | 107 + backend/app/api/routes.py | 39 + backend/app/api/screener.py | 575 ++++ backend/app/api/settings.py | 667 +++++ backend/app/api/signals.py | 100 + backend/app/api/strategy.py | 468 +++ backend/app/api/watchlist.py | 202 ++ backend/app/backtest/__init__.py | 4 + backend/app/backtest/engine.py | 1485 ++++++++++ backend/app/backtest/factor.py | 480 +++ backend/app/backtest/strategy.py | 701 +++++ backend/app/config.py | 61 + backend/app/indicators/__init__.py | 1 + backend/app/indicators/pipeline.py | 1494 ++++++++++ backend/app/jobs/__init__.py | 1 + backend/app/jobs/daily_pipeline.py | 499 ++++ backend/app/main.py | 170 ++ backend/app/secrets_store.py | 96 + backend/app/services/__init__.py | 1 + backend/app/services/backtest.py | 392 +++ backend/app/services/ext_data.py | 483 +++ backend/app/services/ext_pull.py | 216 ++ backend/app/services/extend_history.py | 224 ++ backend/app/services/financial_sync.py | 273 ++ backend/app/services/index_sync.py | 146 + backend/app/services/instrument_sync.py | 122 + backend/app/services/kline_sync.py | 617 ++++ backend/app/services/pipeline_jobs.py | 250 ++ backend/app/services/preferences.py | 250 ++ backend/app/services/quote_service.py | 673 +++++ backend/app/services/screener.py | 585 ++++ backend/app/services/strategy_cache.py | 150 + backend/app/services/watchlist.py | 126 + backend/app/strategy/__init__.py | 0 backend/app/strategy/ai_generator.py | 149 + backend/app/strategy/builtin/__init__.py | 0 backend/app/strategy/builtin/boll_breakout.py | 31 + .../strategy/builtin/broken_board_recovery.py | 35 + .../app/strategy/builtin/bullish_alignment.py | 29 + .../strategy/builtin/consecutive_limit_ups.py | 31 + .../strategy/builtin/high_turnover_surge.py | 34 + .../app/strategy/builtin/limit_up_momentum.py | 34 + .../strategy/builtin/low_volatility_leader.py | 32 + .../app/strategy/builtin/ma_golden_cross.py | 32 + backend/app/strategy/builtin/macd_golden.py | 31 + .../strategy/builtin/n_day_low_reversal.py | 32 + backend/app/strategy/builtin/near_limit_up.py | 55 + .../app/strategy/builtin/oversold_bounce.py | 37 + .../app/strategy/builtin/oversold_reversal.py | 37 + .../strategy/builtin/pullback_ma20_bounce.py | 34 + .../strategy/builtin/pullback_to_support.py | 37 + backend/app/strategy/builtin/strong_open.py | 35 + .../app/strategy/builtin/trend_breakout.py | 42 + .../strategy/builtin/volume_price_surge.py | 32 + backend/app/strategy/config.py | 71 + backend/app/strategy/custom_signals.py | 207 ++ backend/app/strategy/engine.py | 453 +++ backend/app/strategy/monitor.py | 204 ++ backend/app/strategy/prompt_builder.py | 65 + backend/app/tickflow/__init__.py | 1 + backend/app/tickflow/capabilities.py | 75 + backend/app/tickflow/client.py | 72 + backend/app/tickflow/policy.py | 390 +++ backend/app/tickflow/pools.py | 158 + backend/app/tickflow/repository.py | 965 ++++++ backend/app/tickflow/scheduler.py | 66 + backend/pyproject.toml | 65 + backend/scripts/__init__.py | 0 backend/scripts/cleanup_halt_days.py | 96 + .../tests/backtest/test_engine_portfolio.py | 312 ++ .../backtest/test_full_simulation_tail.py | 59 + .../test_strategy_backtest_correctness.py | 163 + backend/uv.lock | 2638 +++++++++++++++++ data/.gitkeep | 0 dev.ps1 | 242 ++ dev.sh | 142 + docker-compose.yml | 16 + docs/screenshots/backtest.png | Bin 0 -> 668676 bytes docs/screenshots/dashboard.png | Bin 0 -> 641420 bytes docs/screenshots/screener.png | Bin 0 -> 528414 bytes docs/strategy-builder-step1.md | 175 ++ docs/strategy-builder-step2.md | 34 + docs/strategy-example.md | 153 + docs/strategy-guide.md | 332 +++ frontend/.gitignore | 5 + frontend/index.html | 19 + frontend/package.json | 42 + frontend/pnpm-lock.yaml | 1917 ++++++++++++ frontend/postcss.config.js | 6 + frontend/public/favicon.svg | 12 + frontend/src/components/CandlestickChart.tsx | 154 + frontend/src/components/ColumnCustomizer.tsx | 24 + frontend/src/components/DatePicker.tsx | 235 ++ .../src/components/EChartsCandlestick.tsx | 1085 +++++++ frontend/src/components/EChartsIntraday.tsx | 592 ++++ frontend/src/components/EmptyState.tsx | 20 + .../src/components/EndpointTestDialog.tsx | 259 ++ .../src/components/ExtDimensionAnalysis.tsx | 436 +++ frontend/src/components/Layout.tsx | 449 +++ .../src/components/ListColumnCustomizer.tsx | 714 +++++ frontend/src/components/Logo.tsx | 59 + frontend/src/components/PageHeader.tsx | 25 + frontend/src/components/StockDailyKChart.tsx | 232 ++ frontend/src/components/StockInfoBar.tsx | 66 + .../src/components/StockIntradayChart.tsx | 120 + frontend/src/components/StockPanel.tsx | 115 + .../src/components/StockPreviewDialog.tsx | 212 ++ frontend/src/components/Toast.tsx | 49 + frontend/src/components/analysis-shared.tsx | 451 +++ .../src/components/data/ActiveJobCard.tsx | 135 + .../components/data/EnrichedRebuildPanel.tsx | 111 + .../components/data/ExtendHistoryPanel.tsx | 98 + .../src/components/data/MinuteSyncConfig.tsx | 189 ++ .../src/components/data/QuoteConfigCard.tsx | 165 ++ .../src/components/data/ScheduleEditor.tsx | 43 + frontend/src/components/data/SchemaModal.tsx | 102 + frontend/src/components/data/SectionTitle.tsx | 61 + .../src/components/data/SettingsModal.tsx | 27 + frontend/src/components/data/Skeleton.tsx | 7 + frontend/src/components/data/StatCard.tsx | 312 ++ .../components/ext-data/CreateExtDialog.tsx | 383 +++ .../src/components/ext-data/EditExtDialog.tsx | 252 ++ .../components/ext-data/ExtDataApiPanel.tsx | 79 + .../components/ext-data/ExtDataPullPanel.tsx | 212 ++ .../components/ext-data/ExtDataStatCard.tsx | 315 ++ .../components/screener/ScreenerFilter.tsx | 162 + .../src/components/screener/ScreenerTable.tsx | 320 ++ .../screener/StrategyBuilderDialog.tsx | 402 +++ .../src/components/screener/StrategyCard.tsx | 198 ++ .../screener/StrategyPoolDialog.tsx | 240 ++ .../screener/StrategySettingsDialog.tsx | 597 ++++ .../screener/StrategyStoreDialog.tsx | 87 + .../stock-table/MiniCandlestick.tsx | 81 + .../components/stock-table/StockDataTable.tsx | 120 + .../src/components/stock-table/primitives.tsx | 163 + .../components/stock-table/useTableSort.ts | 50 + frontend/src/index.css | 79 + frontend/src/lib/analysis-adapter.ts | 341 +++ frontend/src/lib/api.ts | 1273 ++++++++ frontend/src/lib/backtestTask.ts | 223 ++ frontend/src/lib/board.ts | 25 + frontend/src/lib/capability-labels.ts | 15 + frontend/src/lib/cn.ts | 6 + frontend/src/lib/colors.ts | 31 + frontend/src/lib/format.ts | 81 + frontend/src/lib/list-columns.ts | 196 ++ frontend/src/lib/queryKeys.ts | 79 + frontend/src/lib/screener-columns.ts | 128 + frontend/src/lib/stock-table.ts | 108 + frontend/src/lib/storage.ts | 99 + frontend/src/lib/useFinancials.ts | 38 + frontend/src/lib/useQueryConfig.ts | 40 + frontend/src/lib/useQuoteStream.ts | 114 + frontend/src/lib/useSharedMutations.ts | 42 + frontend/src/lib/useSharedQueries.ts | 71 + frontend/src/lib/useStrategyPool.ts | 25 + frontend/src/lib/watchlist-columns.ts | 166 ++ frontend/src/main.tsx | 23 + frontend/src/pages/Analysis.tsx | 291 ++ frontend/src/pages/AnalysisDetail.tsx | 7 + frontend/src/pages/Backtest.tsx | 63 + frontend/src/pages/Branding.tsx | 203 ++ frontend/src/pages/ConceptAnalysis.tsx | 750 +++++ frontend/src/pages/Dashboard.tsx | 517 ++++ frontend/src/pages/Data.tsx | 946 ++++++ frontend/src/pages/Financials.tsx | 143 + frontend/src/pages/Indices.tsx | 335 +++ frontend/src/pages/IndustryAnalysis.tsx | 822 +++++ frontend/src/pages/LimitUpLadder.tsx | 1188 ++++++++ frontend/src/pages/MinuteDataProbe.tsx | 189 ++ frontend/src/pages/Monitor.tsx | 77 + frontend/src/pages/Onboarding.tsx | 14 + frontend/src/pages/Screener.tsx | 819 +++++ frontend/src/pages/Settings.tsx | 82 + frontend/src/pages/StockAnalysis.tsx | 10 + frontend/src/pages/Trading.tsx | 82 + frontend/src/pages/Watchlist.tsx | 1100 +++++++ .../src/pages/backtest/FactorBacktest.tsx | 447 +++ .../src/pages/backtest/StrategyBacktest.tsx | 2213 ++++++++++++++ .../backtest/charts/FactorGroupNavChart.tsx | 124 + .../pages/backtest/charts/FactorICChart.tsx | 88 + .../charts/ReturnDistributionChart.tsx | 63 + .../backtest/charts/StrategyNavChart.tsx | 209 ++ .../src/pages/backtest/charts/useECharts.ts | 37 + .../backtest/components/TradeKlineModal.tsx | 170 ++ frontend/src/pages/settings/AI.tsx | 200 ++ frontend/src/pages/settings/CustomSignals.tsx | 259 ++ frontend/src/pages/settings/ExtPages.tsx | 291 ++ frontend/src/pages/settings/Keys.tsx | 373 +++ frontend/src/pages/settings/MenuSettings.tsx | 278 ++ frontend/src/pages/settings/Monitoring.tsx | 398 +++ frontend/src/pages/settings/System.tsx | 135 + frontend/src/router.tsx | 54 + frontend/src/vite-env.d.ts | 6 + frontend/tailwind.config.ts | 44 + frontend/tsconfig.json | 30 + frontend/tsconfig.node.json | 14 + frontend/vite.config.d.ts | 2 + frontend/vite.config.js | 35 + frontend/vite.config.ts | 36 + tiers.yaml | 46 + 218 files changed, 52566 insertions(+) create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 README.md create mode 100644 VERSION create mode 100644 backend/app/__init__.py create mode 100644 backend/app/api/__init__.py create mode 100644 backend/app/api/analysis.py create mode 100644 backend/app/api/backtest.py create mode 100644 backend/app/api/data.py create mode 100644 backend/app/api/ext_data.py create mode 100644 backend/app/api/financials.py create mode 100644 backend/app/api/indices.py create mode 100644 backend/app/api/intraday.py create mode 100644 backend/app/api/kline.py create mode 100644 backend/app/api/overview.py create mode 100644 backend/app/api/pipeline.py create mode 100644 backend/app/api/routes.py create mode 100644 backend/app/api/screener.py create mode 100644 backend/app/api/settings.py create mode 100644 backend/app/api/signals.py create mode 100644 backend/app/api/strategy.py create mode 100644 backend/app/api/watchlist.py create mode 100644 backend/app/backtest/__init__.py create mode 100644 backend/app/backtest/engine.py create mode 100644 backend/app/backtest/factor.py create mode 100644 backend/app/backtest/strategy.py create mode 100644 backend/app/config.py create mode 100644 backend/app/indicators/__init__.py create mode 100644 backend/app/indicators/pipeline.py create mode 100644 backend/app/jobs/__init__.py create mode 100644 backend/app/jobs/daily_pipeline.py create mode 100644 backend/app/main.py create mode 100644 backend/app/secrets_store.py create mode 100644 backend/app/services/__init__.py create mode 100644 backend/app/services/backtest.py create mode 100644 backend/app/services/ext_data.py create mode 100644 backend/app/services/ext_pull.py create mode 100644 backend/app/services/extend_history.py create mode 100644 backend/app/services/financial_sync.py create mode 100644 backend/app/services/index_sync.py create mode 100644 backend/app/services/instrument_sync.py create mode 100644 backend/app/services/kline_sync.py create mode 100644 backend/app/services/pipeline_jobs.py create mode 100644 backend/app/services/preferences.py create mode 100644 backend/app/services/quote_service.py create mode 100644 backend/app/services/screener.py create mode 100644 backend/app/services/strategy_cache.py create mode 100644 backend/app/services/watchlist.py create mode 100644 backend/app/strategy/__init__.py create mode 100644 backend/app/strategy/ai_generator.py create mode 100644 backend/app/strategy/builtin/__init__.py create mode 100644 backend/app/strategy/builtin/boll_breakout.py create mode 100644 backend/app/strategy/builtin/broken_board_recovery.py create mode 100644 backend/app/strategy/builtin/bullish_alignment.py create mode 100644 backend/app/strategy/builtin/consecutive_limit_ups.py create mode 100644 backend/app/strategy/builtin/high_turnover_surge.py create mode 100644 backend/app/strategy/builtin/limit_up_momentum.py create mode 100644 backend/app/strategy/builtin/low_volatility_leader.py create mode 100644 backend/app/strategy/builtin/ma_golden_cross.py create mode 100644 backend/app/strategy/builtin/macd_golden.py create mode 100644 backend/app/strategy/builtin/n_day_low_reversal.py create mode 100644 backend/app/strategy/builtin/near_limit_up.py create mode 100644 backend/app/strategy/builtin/oversold_bounce.py create mode 100644 backend/app/strategy/builtin/oversold_reversal.py create mode 100644 backend/app/strategy/builtin/pullback_ma20_bounce.py create mode 100644 backend/app/strategy/builtin/pullback_to_support.py create mode 100644 backend/app/strategy/builtin/strong_open.py create mode 100644 backend/app/strategy/builtin/trend_breakout.py create mode 100644 backend/app/strategy/builtin/volume_price_surge.py create mode 100644 backend/app/strategy/config.py create mode 100644 backend/app/strategy/custom_signals.py create mode 100644 backend/app/strategy/engine.py create mode 100644 backend/app/strategy/monitor.py create mode 100644 backend/app/strategy/prompt_builder.py create mode 100644 backend/app/tickflow/__init__.py create mode 100644 backend/app/tickflow/capabilities.py create mode 100644 backend/app/tickflow/client.py create mode 100644 backend/app/tickflow/policy.py create mode 100644 backend/app/tickflow/pools.py create mode 100644 backend/app/tickflow/repository.py create mode 100644 backend/app/tickflow/scheduler.py create mode 100644 backend/pyproject.toml create mode 100644 backend/scripts/__init__.py create mode 100644 backend/scripts/cleanup_halt_days.py create mode 100644 backend/tests/backtest/test_engine_portfolio.py create mode 100644 backend/tests/backtest/test_full_simulation_tail.py create mode 100644 backend/tests/backtest/test_strategy_backtest_correctness.py create mode 100644 backend/uv.lock create mode 100644 data/.gitkeep create mode 100644 dev.ps1 create mode 100755 dev.sh create mode 100644 docker-compose.yml create mode 100644 docs/screenshots/backtest.png create mode 100644 docs/screenshots/dashboard.png create mode 100644 docs/screenshots/screener.png create mode 100644 docs/strategy-builder-step1.md create mode 100644 docs/strategy-builder-step2.md create mode 100644 docs/strategy-example.md create mode 100644 docs/strategy-guide.md create mode 100644 frontend/.gitignore create mode 100644 frontend/index.html create mode 100644 frontend/package.json create mode 100644 frontend/pnpm-lock.yaml create mode 100644 frontend/postcss.config.js create mode 100644 frontend/public/favicon.svg create mode 100644 frontend/src/components/CandlestickChart.tsx create mode 100644 frontend/src/components/ColumnCustomizer.tsx create mode 100644 frontend/src/components/DatePicker.tsx create mode 100644 frontend/src/components/EChartsCandlestick.tsx create mode 100644 frontend/src/components/EChartsIntraday.tsx create mode 100644 frontend/src/components/EmptyState.tsx create mode 100644 frontend/src/components/EndpointTestDialog.tsx create mode 100644 frontend/src/components/ExtDimensionAnalysis.tsx create mode 100644 frontend/src/components/Layout.tsx create mode 100644 frontend/src/components/ListColumnCustomizer.tsx create mode 100644 frontend/src/components/Logo.tsx create mode 100644 frontend/src/components/PageHeader.tsx create mode 100644 frontend/src/components/StockDailyKChart.tsx create mode 100644 frontend/src/components/StockInfoBar.tsx create mode 100644 frontend/src/components/StockIntradayChart.tsx create mode 100644 frontend/src/components/StockPanel.tsx create mode 100644 frontend/src/components/StockPreviewDialog.tsx create mode 100644 frontend/src/components/Toast.tsx create mode 100644 frontend/src/components/analysis-shared.tsx create mode 100644 frontend/src/components/data/ActiveJobCard.tsx create mode 100644 frontend/src/components/data/EnrichedRebuildPanel.tsx create mode 100644 frontend/src/components/data/ExtendHistoryPanel.tsx create mode 100644 frontend/src/components/data/MinuteSyncConfig.tsx create mode 100644 frontend/src/components/data/QuoteConfigCard.tsx create mode 100644 frontend/src/components/data/ScheduleEditor.tsx create mode 100644 frontend/src/components/data/SchemaModal.tsx create mode 100644 frontend/src/components/data/SectionTitle.tsx create mode 100644 frontend/src/components/data/SettingsModal.tsx create mode 100644 frontend/src/components/data/Skeleton.tsx create mode 100644 frontend/src/components/data/StatCard.tsx create mode 100644 frontend/src/components/ext-data/CreateExtDialog.tsx create mode 100644 frontend/src/components/ext-data/EditExtDialog.tsx create mode 100644 frontend/src/components/ext-data/ExtDataApiPanel.tsx create mode 100644 frontend/src/components/ext-data/ExtDataPullPanel.tsx create mode 100644 frontend/src/components/ext-data/ExtDataStatCard.tsx create mode 100644 frontend/src/components/screener/ScreenerFilter.tsx create mode 100644 frontend/src/components/screener/ScreenerTable.tsx create mode 100644 frontend/src/components/screener/StrategyBuilderDialog.tsx create mode 100644 frontend/src/components/screener/StrategyCard.tsx create mode 100644 frontend/src/components/screener/StrategyPoolDialog.tsx create mode 100644 frontend/src/components/screener/StrategySettingsDialog.tsx create mode 100644 frontend/src/components/screener/StrategyStoreDialog.tsx create mode 100644 frontend/src/components/stock-table/MiniCandlestick.tsx create mode 100644 frontend/src/components/stock-table/StockDataTable.tsx create mode 100644 frontend/src/components/stock-table/primitives.tsx create mode 100644 frontend/src/components/stock-table/useTableSort.ts create mode 100644 frontend/src/index.css create mode 100644 frontend/src/lib/analysis-adapter.ts create mode 100644 frontend/src/lib/api.ts create mode 100644 frontend/src/lib/backtestTask.ts create mode 100644 frontend/src/lib/board.ts create mode 100644 frontend/src/lib/capability-labels.ts create mode 100644 frontend/src/lib/cn.ts create mode 100644 frontend/src/lib/colors.ts create mode 100644 frontend/src/lib/format.ts create mode 100644 frontend/src/lib/list-columns.ts create mode 100644 frontend/src/lib/queryKeys.ts create mode 100644 frontend/src/lib/screener-columns.ts create mode 100644 frontend/src/lib/stock-table.ts create mode 100644 frontend/src/lib/storage.ts create mode 100644 frontend/src/lib/useFinancials.ts create mode 100644 frontend/src/lib/useQueryConfig.ts create mode 100644 frontend/src/lib/useQuoteStream.ts create mode 100644 frontend/src/lib/useSharedMutations.ts create mode 100644 frontend/src/lib/useSharedQueries.ts create mode 100644 frontend/src/lib/useStrategyPool.ts create mode 100644 frontend/src/lib/watchlist-columns.ts create mode 100644 frontend/src/main.tsx create mode 100644 frontend/src/pages/Analysis.tsx create mode 100644 frontend/src/pages/AnalysisDetail.tsx create mode 100644 frontend/src/pages/Backtest.tsx create mode 100644 frontend/src/pages/Branding.tsx create mode 100644 frontend/src/pages/ConceptAnalysis.tsx create mode 100644 frontend/src/pages/Dashboard.tsx create mode 100644 frontend/src/pages/Data.tsx create mode 100644 frontend/src/pages/Financials.tsx create mode 100644 frontend/src/pages/Indices.tsx create mode 100644 frontend/src/pages/IndustryAnalysis.tsx create mode 100644 frontend/src/pages/LimitUpLadder.tsx create mode 100644 frontend/src/pages/MinuteDataProbe.tsx create mode 100644 frontend/src/pages/Monitor.tsx create mode 100644 frontend/src/pages/Onboarding.tsx create mode 100644 frontend/src/pages/Screener.tsx create mode 100644 frontend/src/pages/Settings.tsx create mode 100644 frontend/src/pages/StockAnalysis.tsx create mode 100644 frontend/src/pages/Trading.tsx create mode 100644 frontend/src/pages/Watchlist.tsx create mode 100644 frontend/src/pages/backtest/FactorBacktest.tsx create mode 100644 frontend/src/pages/backtest/StrategyBacktest.tsx create mode 100644 frontend/src/pages/backtest/charts/FactorGroupNavChart.tsx create mode 100644 frontend/src/pages/backtest/charts/FactorICChart.tsx create mode 100644 frontend/src/pages/backtest/charts/ReturnDistributionChart.tsx create mode 100644 frontend/src/pages/backtest/charts/StrategyNavChart.tsx create mode 100644 frontend/src/pages/backtest/charts/useECharts.ts create mode 100644 frontend/src/pages/backtest/components/TradeKlineModal.tsx create mode 100644 frontend/src/pages/settings/AI.tsx create mode 100644 frontend/src/pages/settings/CustomSignals.tsx create mode 100644 frontend/src/pages/settings/ExtPages.tsx create mode 100644 frontend/src/pages/settings/Keys.tsx create mode 100644 frontend/src/pages/settings/MenuSettings.tsx create mode 100644 frontend/src/pages/settings/Monitoring.tsx create mode 100644 frontend/src/pages/settings/System.tsx create mode 100644 frontend/src/router.tsx create mode 100644 frontend/src/vite-env.d.ts create mode 100644 frontend/tailwind.config.ts create mode 100644 frontend/tsconfig.json create mode 100644 frontend/tsconfig.node.json create mode 100644 frontend/vite.config.d.ts create mode 100644 frontend/vite.config.js create mode 100644 frontend/vite.config.ts create mode 100644 tiers.yaml diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..5ed6b31 --- /dev/null +++ b/.env.example @@ -0,0 +1,18 @@ +# ===== TickFlow ===== +# 留空或不填则启用 Free 试用模式(TickFlow.free()),仅能拿历史日 K 单股数据 +TICKFLOW_API_KEY= + +# ===== AI(可选,留空跳过 AI 功能) ===== +AI_PROVIDER=openai_compat # openai_compat | ollama +AI_BASE_URL=https://api.deepseek.com/v1 +AI_API_KEY= +AI_MODEL=deepseek-chat +AI_DAILY_TOKEN_BUDGET=500000 + +# ===== Server ===== +HOST=0.0.0.0 +PORT=3018 +LOG_LEVEL=INFO + +# ===== Data ===== +DATA_DIR=./data diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..32d0b57 --- /dev/null +++ b/.gitignore @@ -0,0 +1,86 @@ +# ===== Python ===== +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +.venv/ +venv/ +env/ +.python-version +.pytest_cache/ +.mypy_cache/ +.ruff_cache/ +.coverage +htmlcov/ +dist/ +build/ +*.egg-info/ + +# ===== uv ===== +.uv/ + +# ===== Node / pnpm ===== +node_modules/ +.pnpm-store/ +.pnpm-debug.log* +.npm/ +*.log + +# ===== Vite ===== +frontend/dist/ +frontend/.vite/ +backend/static/ +backend/app/static/ + +# ===== IDE ===== +.idea/ +.vscode/ +*.swp +*.swo +.DS_Store + +# ===== Project data (Parquet/DuckDB) ===== +backend/data/** +!backend/data/.gitkeep +data/** +!data/.gitkeep + +# ===== Secrets ===== +.env +.env.local +.env.*.local +backend/.env + +# ===== User-derived prompts ===== +backend/user_prompts/ + +# ===== Browser automation ===== +.playwright-mcp/ + +# ===== AI IDE ===== +.trae/ + +# ===== TypeScript build cache ===== +frontend/tsconfig*.tsbuildinfo + +# ===== Data files ===== +*.xlsx + +# ===== Private deploy / 服务器私有信息(不开源) ===== +DEPLOY.md +deploy.sh + +# ===== 内部设计文档(不开源) ===== +DESIGN.md +DESIGN-proposal.md +CLAUDE.md + +# ===== 私人脚本(不开源) ===== +docs/zhihu/ + +# ===== 用户自定义策略(私有,不开源) ===== +data/strategies/custom/ + +# ===== 临时 / 调试产物 ===== +backend._recheck*.py diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e37e509 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,31 @@ +# 两阶段构建:前端 dist 拷进后端镜像,单容器运行 +# === Stage 1: 前端构建 === +FROM node:20-alpine AS frontend-builder +WORKDIR /build +RUN corepack enable && corepack prepare pnpm@9 --activate +COPY frontend/package.json frontend/pnpm-lock.yaml* ./ +RUN pnpm install --frozen-lockfile || pnpm install +COPY frontend/ ./ +RUN pnpm build + +# === Stage 2: Python 运行时 === +FROM python:3.11-slim AS runtime +WORKDIR /app + +# 安装 uv(快) +RUN pip install --no-cache-dir uv + +# Backend deps +COPY backend/pyproject.toml backend/uv.lock* ./ +RUN uv sync --frozen --no-dev || uv sync --no-dev + +# Backend code +COPY backend/app ./app +COPY tiers.yaml /app/tiers.yaml + +# Frontend 静态产物 +COPY --from=frontend-builder /build/dist ./static + +ENV PYTHONPATH=/app +EXPOSE 3018 +CMD ["uv", "run", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "3018"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f7888c9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 tf-stocks-panel contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..93c2819 --- /dev/null +++ b/README.md @@ -0,0 +1,304 @@ +
+ +# 📈 tf-stocks-panel + +**自托管、零运维的 A 股「选股 + 监控 + 回测」量化工作台** + +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE) +[![Python](https://img.shields.io/badge/Python-≥3.11-blue.svg)](https://www.python.org/) +[![React](https://img.shields.io/badge/React-18-61dafb.svg)](https://react.dev/) +[![Data: TickFlow](https://img.shields.io/badge/Data-TickFlow-00b386.svg)](https://tickflow.org/auth/register?ref=V3KDKGXPEA) +[![Deploy: Docker](https://img.shields.io/badge/Deploy-Docker-2496ed.svg)](./Dockerfile) + +基于 [TickFlow](https://tickflow.org/auth/register?ref=V3KDKGXPEA) 数据 · 🚀 **开箱即用**(单容器 / Free 模式无需 Key) +能力驱动,适配 Free → Expert 全档位订阅 · 🔌 **自由接入第三方扩展数据**(例如 Tushare、自有量化项目数据) + +**[核心功能](#-核心功能)** · **[快速开始](#-快速开始)** · **[配置](#️-配置)** · **[路线图](#-路线图)** + +
+ +--- + +## 🎯 项目定位 + +让任何**个人散户 / 量化爱好者**,**零运维**地拥有一套**与自己订阅档位严格匹配**的 A 股分析、选股、监控工作台。 +基于 [TickFlow](https://tickflow.org/auth/register?ref=V3KDKGXPEA) Key **低成本**获取数据。**填写邀请码 `V3KDKGXPEA` 免费领取概念行业等扩展数据**。
+**任意接入第三方数据**(Tushare 等),页面可视化自定义配置扩展数据表。 + +**项目所需配置**: + +| 配置项 | 说明 | 是否必填 | +| :--- | :--- | :--- | +| **TickFlow API Key** | 数据源凭证,留空启用 Free 模式(无需注册即可体验) | 可选 | +| **AI 大模型 API Key** | 用于 AI 生成策略、个股分析(开发中)、行情分析(开发中),任意 OpenAI 兼容接口,留空关闭 | 可选 | + + + + + + + + + + + + +
看板 Dashboard选股 Screener回测 Backtest
看板页面选股/策略页回测页
+ +> ### ⚠️ 🚧 项目持续优化,功能陆续开放,敬请期待。 + +> **明确不做**:不对标同花顺/通达信的全功能股票软件;不内置任何「AI 荐股 / 涨停预测」。 + +--- + +## ✨ 核心功能 + +### 🔍 选股引擎(Screener) + +**20 个内置策略** —— 每个策略是一个独立 Python 文件(`backend/app/strategy/builtin/`),基于 Polars 表达式实现: + +| 类型 | 代表策略 | +| :--- | :--- | +| 趋势 | 趋势突破 · 均线多头 · 缩量回踩 | +| 形态 | MA 金叉 · MACD 金叉放量 · 布林突破 | +| 量价 | 量价齐升 · 高换手强势 · 强势高开 | +| 涨停 | 连板股 · 断板反包 · 逼近涨停 · 涨停动量 | +| 反转 | 超跌反弹 · 超卖反转 · 新低反转 | +| 波动 | 低波动龙头 · 回踩 MA20 反弹 | + +- **自定义信号系统** —— 在 UI 上用 `字段 + 操作符 + 阈值` 组合(entry / exit / both),编译成 Polars 表达式热加载,**无需写代码**即可定义自己的买卖信号。 +- **策略商店** —— 内置策略 + 用户自定义策略统一管理,支持参数覆盖(`params` 暴露阈值)。 + +#### ➕ 添加自己的策略 + +除 20 个内置策略外,你可以用两种方式扩展: + +| 方式 | 说明 | 前提 | +| :--- | :--- | :--- | +| **🤖 AI 生成** | 用自然语言描述策略思路,LLM 读取 [strategy-guide.md](./docs/strategy-guide.md) 自动生成完整 Polars 策略文件(经 `ast` 安全校验,限定 `import polars as pl`)。生成后落入 `data/strategies/ai/`,即刻可用 | 需先在 [配置](#️-配置) 中填入 AI Key | +| **📝 代码自定义 / 策略迁移** | 参照 [策略开发指南](./docs/strategy-guide.md) 的文件结构模板,把你**已有的自有策略**改写为 Polars 文件放入 `data/strategies/custom/`(文件名/ID 建议 `custom_时间戳`),引擎自动发现加载——**轻松迁移你现成的量化项目策略**,无需从头重写 | 无 | +| **🎛️ 自定义信号配置** | 不写代码,在 UI 上用 `字段 + 操作符 + 阈值` 组合(entry / exit / both),编译成 Polars 表达式热加载,即可定义自己的买卖信号 | 无 | + +> 引擎按 `source` 标记来源:`builtin`(内置)/ `custom`(手写或迁移)/ `ai`(生成),三者统一进入策略商店管理。 + +### 📊 指标流水线(Indicators) + +原生 Polars 向量化计算,全 A 股一次扫表落盘为 enriched Parquet: + +| 分类 | 指标 | +| :--- | :--- | +| 均线系 | MA(5/10/20/30/60)· EMA(5/10/12/20/26/30/60) | +| 趋势系 | MACD(DIF/DEA/HIST)· 动量(5/10/20/30/60d)· 布林带(上/下轨) | +| 震荡系 | RSI(可配周期)· KDJ(K/D/J) | +| 波动系 | ATR(14)· 年化波动率(20d)· 振幅 | +| 量能系 | 量比(5d/10d)· 量均线 | +| 涨跌停 | 涨停信号 · 连板数 · 涨跌幅 · 涨跌额 | +| 原子信号 | MA 金叉/死叉 · MA20 突破/跌破 · MACD 金叉/死叉 · N 日新高/新低 · 布林突破 | +| 复权 | 基于除权因子自动计算前复权(`ex_factor` / `cum_factor`),回测与指标一致 | + +### 🧪 回测引擎(Backtest) + +基于 vectorbt(全项目**唯一**一处 pandas 出现地): + +- **三种回测模式**:个股 · 策略组合 · 自由信号组合 +- **真实约束**:T+1 · 手续费 · 滑点(基点) · 止损 · 最大持仓天数 +- **组合管理**:最大持仓数 · 最大敞口 · 等权 / 自定义仓位 +- **SSE 流式进度**:长任务实时推送进度,支持刷新 / 切页后**重连恢复**(相同参数任务只启动一次) +- **统计输出**:净值曲线 · 夏普 · 最大回撤 · 胜率 · 每笔交易明细 + +### 📡 实时监控(Strategy Monitor) + +- **盘中 SSE 推送**:行情刷新(`quotes_updated`)+ 策略告警(`strategy_alert`)双事件流,前端实时弹通知 +- **策略监控**:订阅策略的 entry / exit 信号 + 自定义提醒条件(如 `rsi_14 > 80`),命中即推送 +- **Webhook 告警**:命中规则后可选推送外部 webhook + +### 🤖 AI 策略生成(可选) + +- **自然语言 → 策略代码**:用一句话描述策略思路,LLM 读取 `docs/strategy-guide.md` 生成完整 Polars 策略文件 +- **沙箱约束**:生成代码经 `ast` 校验、限定 `import polars as pl`,避免逐行循环,优先向量化表达 +- **可插拔**:留空 AI 配置即跳过整个模块,不影响核心功能 + +### 🧰 数据与扩展 + +- **多源数据**:TickFlow 日 K / 分钟 K / 指数 / 财务(利润 / 资产负债 / 现金流)/ 自选行情 +- **🔌 第三方数据接入(重点)** —— TickFlow 之外的数据也能用: + - 支持 **Tushare** 等第三方数据源,通过 **HTTP 定时拉取**自动入库 + - 支持 **CSV / Excel 上传** · **JSON 写入**,自动 schema 发现与符号归一 + - **页面可视化配置**扩展数据表,无需改代码 + - 可接入**你自己的量化项目数据**,统一并入 DuckDB 查询面,与内置数据同台分析 +- **盘后定时管道**:APScheduler 15:30 CST 自动拉日 K + 重算 enriched 表 + 跑监控 +- **令牌桶限流**:适配各档位 rpm / batch 上限,批量合并 + 增量拉取,同一份数据多面板复用 + +--- + +## 🚀 快速开始 + +### 前置依赖 + +| 工具 | 版本 | 安装 | +| :--- | :--- | :--- | +| Python | ≥ 3.11 | [python.org](https://www.python.org/) | +| Node | ≥ 20 | [nodejs.org](https://nodejs.org/) | +| [`uv`](https://docs.astral.sh/uv/) | latest | `curl -LsSf https://astral.sh/uv/install.sh \| sh` | +| `pnpm` | 9 | `npm i -g pnpm` 或 `corepack enable && corepack prepare pnpm@9 --activate` | + +### 方式 A:Docker(最省心,生产推荐) + +```bash +cp .env.example .env # 按需填写 Key(留空即 Free 模式,可直接体验) +docker compose up --build +# 打开 http://localhost:3018 +``` + +### 方式 B:Dev 模式(二次开发) + +```bash +cp .env.example .env # 填 TICKFLOW_API_KEY,留空则启用 Free 试用 +``` + +**一键启动**(推荐,自动检查依赖 / 释放端口 / 同时起前后端,Ctrl-C 一并关闭): + +| 平台 | 命令 | +| :--- | :--- | +| **macOS / Linux** | `./dev.sh` | +| **Windows (PowerShell)** | `.\dev.ps1` | + +首次运行会自动安装前后端依赖(约 1-2 分钟),之后直接启动: + +- 后端 → +- 前端 → + +自定义端口:`BACKEND_PORT=8000 FRONTEND_PORT=5173 ./dev.sh`(Windows:`.\dev.ps1 -BackendPort 8000 -FrontendPort 5173`) + +
+手动分别启动(备选) + +```bash +# 终端 1:后端 +cd backend +uv sync +uv run uvicorn app.main:app --reload --port 3018 + +# 终端 2:前端 +cd frontend +pnpm install +pnpm dev # http://localhost:3011 +``` + +
+ +> **启用回测**:`cd backend && uv sync --extra backtest` +> vectorbt → numba 体积较大,故作为可选 extras。macOS / Intel 无预构建 wheel 时需 `brew install cmake` 现场编译。 + +--- + +## 🧭 第一次使用 + +1. 打开面板 → **设置 → 凭据与能力** → 点 **重新检测**,确认 Tier Label +2. 点 **立即跑盘后管道** —— 拉日 K + 计算 enriched 表 + - **Free 用户**:只同步内置 DEMO_SYMBOLS(浦发 / 招商 / 茅台等 10 只) + - **Starter+**:同步全 A 或可获取的 instruments 列表 +3. **自选**页:添加跟踪标的;点代码进 **K 线**页看蜡烛图 + 买卖点 +4. **选股**页:点任一内置策略卡片即时扫描;或用自定义信号组合条件 +5. **回测**页:选策略 / 信号 + 时间区间 → 跑回测 → 看净值 / 夏普 / 交易明细(SSE 实时进度) +6. **监控**页:配置告警规则,盘中 SSE 推送行情与策略信号;命中后写入告警日志(可选 webhook) + +--- + +## ⚙️ 配置 + +所有配置通过项目根目录的 `.env` 文件读取(复制 `.env.example` 开始)。配置也可在面板 **设置** 页面内修改。 + +### 数据源:TickFlow + +TickFlow 提供订阅制 A 股数据。**留空 `TICKFLOW_API_KEY` 即启用 Free 模式,无需注册即可体验**。 + +```ini +TICKFLOW_API_KEY= # 留空 = Free 模式;填入 Key = 按订阅档位解锁 +``` + +> 完整能力矩阵见 [tickflow.org/pricing](https://tickflow.org/pricing/)。系统启动时会自动探测你的真实能力集,UI 显示「≈ Pro」等友好标签。 + +### AI(可选):策略生成 + +AI 模块用于「自然语言生成策略代码」。**所有配置留空即跳过 AI 功能,不影响核心使用**。支持任何 **OpenAI 兼容接口**: + +```ini +AI_PROVIDER=openai_compat # openai_compat | ollama +AI_BASE_URL=https://api.deepseek.com/v1 +AI_API_KEY= # 留空 = 关闭 AI +AI_MODEL=deepseek-chat +AI_DAILY_TOKEN_BUDGET=500000 # 每日 token 预算上限 +``` + +> 切换 `AI_PROVIDER=ollama` 时无需 `AI_API_KEY`,适合本地部署大模型。 + +### 服务与数据 + +```ini +HOST=0.0.0.0 # 监听地址 +PORT=3018 # 服务端口 +LOG_LEVEL=INFO # DEBUG | INFO | WARNING | ERROR +DATA_DIR=./data # Parquet / DuckDB 数据存储目录 +``` + +--- + +## 🏗️ 技术栈 + +| 层 | 选型 | +| :--- | :--- | +| **后端** | FastAPI · Pydantic v2 · APScheduler · sse-starlette | +| **数据** | Polars(计算)· DuckDB(查询)· Parquet(存储)· PyArrow | +| **回测** | vectorbt(全项目唯一 pandas 边界) | +| **数据源** | [TickFlow](https://tickflow.org/auth/register?ref=V3KDKGXPEA) 官方 SDK(`tickflow[all]`) | +| **AI**(可选) | OpenAI 兼容接口(DeepSeek / 通义 / Ollama 等) | +| **前端** | React 18 · Vite · TypeScript · Tailwind CSS · Framer Motion · Tanstack Query · Lightweight Charts · ECharts · dnd-kit | +| **部署** | Docker 两阶段构建,前端 dist 拷进后端镜像,**单容器** | + +--- + +## 🗺️ 路线图 + +| Phase | 内容 | 状态 | +| :--- | :--- | :--- | +| **0** | 仓库骨架 / FastAPI 壳 / Vite + React SPA / Docker 一键起 | ✅ | +| **1** | 能力探测 + Kline 同步 + K 线分析页 | ✅ | +| **2** | Polars enriched 流水线 + Screener + 信号扫描 | ✅ | +| **3** | vectorbt 回测 + T+1 + 手续费 + 止损 + max-hold | ✅ | +| **4** | 监控引擎 + 告警规则 + Webhook + APScheduler 盘后定时 | ✅ | +| **v2** | 自定义信号 / 策略商店 / AI 策略生成 / 外部数据源插件 / 早晚报 / Onboarding | 🚧 | + +--- + +## 📚 文档 + +- [docs/strategy-guide.md](./docs/strategy-guide.md) —— 策略开发指南(AI 生成器与手写策略的规范) +- [docs/](./docs) —— 策略构建步骤、示例 + +--- + +## 🤝 贡献 + +欢迎 Issue 和 PR。本地开发: + +```bash +cd backend && uv sync --extra backtest # 含回测依赖 +cd ../frontend && pnpm install && pnpm dev +``` + +新增内置策略:在 `backend/app/strategy/builtin/` 参照现有策略文件,实现 `StrategyDef` 即可被引擎自动发现。 + +--- + +## ⚠️ 免责声明 + +本项目仅供**学习与量化研究**,**不构成任何投资建议**。回测结果不代表未来收益。A 股有风险,入市需谨慎。数据准确性以数据源 TickFlow 官方为准。 + +--- + +## 📄 License + +[MIT](./LICENSE) © tf-stocks-panel contributors + +本项目依赖 [TickFlow](https://tickflow.org/auth/register?ref=V3KDKGXPEA) 提供数据服务,使用前请遵守其服务条款。 diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..02dc6f6 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +v0.1.19 diff --git a/backend/app/__init__.py b/backend/app/__init__.py new file mode 100644 index 0000000..b5b011b --- /dev/null +++ b/backend/app/__init__.py @@ -0,0 +1,3 @@ +"""TF-Stocks-Panel backend.""" + +__version__ = "0.1.0" diff --git a/backend/app/api/__init__.py b/backend/app/api/__init__.py new file mode 100644 index 0000000..8a5a42a --- /dev/null +++ b/backend/app/api/__init__.py @@ -0,0 +1 @@ +"""FastAPI 路由汇总。""" diff --git a/backend/app/api/analysis.py b/backend/app/api/analysis.py new file mode 100644 index 0000000..18b572e --- /dev/null +++ b/backend/app/api/analysis.py @@ -0,0 +1,204 @@ +"""自定义分析菜单 API。""" +from __future__ import annotations + +import json +from datetime import datetime +from pathlib import Path +from typing import Literal + +from fastapi import APIRouter, HTTPException, Request +from pydantic import BaseModel, Field + +from app.services.ext_data import ExtConfigStore + +router = APIRouter(prefix="/api/analysis-menus", tags=["analysis-menus"]) + + +class AnalysisColumn(BaseModel): + field: str + label: str = "" + type: Literal["string", "number", "percent", "amount", "date"] = "string" + width: int | None = None + sortable: bool = False + precision: int | None = None + format: str | None = None + aggregate: Literal["count", "avg", "sum", "min", "max"] | None = None + visible: bool = True + + +class DefaultSort(BaseModel): + field: str + order: Literal["asc", "desc"] = "desc" + + +class AnalysisMenu(BaseModel): + id: str = Field(..., min_length=1, max_length=64, pattern=r"^[a-zA-Z0-9_]+$") + label: str = Field(..., min_length=1, max_length=64) + icon: str = "chart" + data_source: str = Field(..., min_length=1) + template: Literal["dimension_rank", "ranking", "table"] = "dimension_rank" + dimension_field: str | None = None + rank_field: str | None = None + group_columns: list[AnalysisColumn] = Field(default_factory=list) + detail_columns: list[AnalysisColumn] = Field(default_factory=list) + default_sort: DefaultSort | None = None + visible: bool = True + order: int = 0 + created_at: str | None = None + updated_at: str | None = None + builtin: bool = False + + +class UpsertAnalysisMenu(BaseModel): + label: str = Field(..., min_length=1, max_length=64) + icon: str = "chart" + data_source: str = Field(..., min_length=1) + template: Literal["dimension_rank", "ranking", "table"] = "dimension_rank" + dimension_field: str | None = None + rank_field: str | None = None + group_columns: list[AnalysisColumn] = Field(default_factory=list) + detail_columns: list[AnalysisColumn] = Field(default_factory=list) + default_sort: DefaultSort | None = None + visible: bool = True + order: int = 0 + + +class ReorderMenusReq(BaseModel): + ids: list[str] = Field(..., min_length=1) + + +def _data_dir(request: Request) -> Path: + return request.app.state.repo.store.data_dir + + +def _base_dir(request: Request) -> Path: + return _data_dir(request) / "analysis_menus" + + +def _path(request: Request, menu_id: str) -> Path: + return _base_dir(request) / f"{menu_id}.json" + + +def _load_saved(request: Request) -> list[AnalysisMenu]: + base = _base_dir(request) + if not base.exists(): + return [] + items: list[AnalysisMenu] = [] + for p in sorted(base.glob("*.json")): + try: + raw = json.loads(p.read_text(encoding="utf-8")) + items.append(AnalysisMenu(**raw)) + except Exception: + continue + return items + + +def _ordered(items: list[AnalysisMenu]) -> list[AnalysisMenu]: + return sorted(items, key=lambda m: (m.order, m.label, m.id)) + + +def _save(request: Request, menu: AnalysisMenu) -> AnalysisMenu: + now = datetime.now().isoformat() + if not menu.created_at: + menu.created_at = now + menu.updated_at = now + menu.builtin = False + base = _base_dir(request) + base.mkdir(parents=True, exist_ok=True) + _path(request, menu.id).write_text( + json.dumps(menu.model_dump(), ensure_ascii=False, indent=2), + encoding="utf-8", + ) + return menu + + +def _default_menus(request: Request) -> list[AnalysisMenu]: + ext_store = ExtConfigStore(_data_dir(request)) + menus: list[AnalysisMenu] = [] + for cfg in ext_store.load_all(): + fields = cfg.fields + concept = next((f for f in fields if "概念" in f.name or "概念" in f.label or "concept" in f.name.lower()), None) + if concept: + detail_names = ["股票简称", "股票代码", concept.name, "人气排名", "资金流向", "PE", "PB"] + detail_columns = [] + for name in detail_names: + f = next((x for x in fields if x.name == name), None) + if not f: + continue + is_num = f.dtype in ("int", "float") + detail_columns.append(AnalysisColumn( + field=f.name, + label=f.label or f.name, + type="number" if is_num else "string", + sortable=is_num, + precision=2 if f.dtype == "float" else None, + )) + menus.append(AnalysisMenu( + id="concept_analysis", + label="概念分析", + icon="tags", + data_source=cfg.id, + template="dimension_rank", + dimension_field=concept.name, + group_columns=[ + AnalysisColumn(field="__dimension", label="概念"), + AnalysisColumn(field="__count", label="股票数", type="number", sortable=True), + ], + detail_columns=detail_columns, + default_sort=DefaultSort(field="人气排名", order="asc") if any(c.field == "人气排名" for c in detail_columns) else None, + order=100, + builtin=True, + )) + break + return menus + + +@router.get("") +def list_menus(request: Request): + saved = _load_saved(request) + saved_ids = {m.id for m in saved} + defaults = [m for m in _default_menus(request) if m.id not in saved_ids] + return {"items": _ordered(saved + defaults)} + + +@router.get("/{menu_id}") +def get_menu(request: Request, menu_id: str): + for menu in _ordered(_load_saved(request) + _default_menus(request)): + if menu.id == menu_id: + return menu + raise HTTPException(404, f"分析菜单 '{menu_id}' 不存在") + + +@router.post("/reorder") +def reorder_menus(request: Request, body: ReorderMenusReq): + saved = {m.id: m for m in _load_saved(request)} + defaults = {m.id: m for m in _default_menus(request)} + for idx, menu_id in enumerate(body.ids): + menu = saved.get(menu_id) or defaults.get(menu_id) + if not menu: + continue + menu.order = idx + _save(request, menu) + return {"items": _ordered(_load_saved(request))} + + +@router.post("/{menu_id}") +def upsert_menu(request: Request, menu_id: str, body: UpsertAnalysisMenu): + if not menu_id.replace("_", "").isalnum(): + raise HTTPException(400, "菜单标识只能包含字母、数字和下划线") + existing = next((m for m in _load_saved(request) if m.id == menu_id), None) + menu = AnalysisMenu( + id=menu_id, + created_at=existing.created_at if existing else None, + **body.model_dump(), + ) + return _save(request, menu) + + +@router.delete("/{menu_id}") +def delete_menu(request: Request, menu_id: str): + p = _path(request, menu_id) + if not p.exists(): + raise HTTPException(404, f"分析菜单 '{menu_id}' 不存在或为默认菜单") + p.unlink() + return {"status": "deleted"} diff --git a/backend/app/api/backtest.py b/backend/app/api/backtest.py new file mode 100644 index 0000000..216a360 --- /dev/null +++ b/backend/app/api/backtest.py @@ -0,0 +1,461 @@ +"""回测 API — 信号回测 + 因子回测 + 策略回测。""" +from __future__ import annotations + +import asyncio +import json +import queue +import threading +from dataclasses import asdict +from datetime import date, timedelta +from typing import Literal + +from fastapi import APIRouter, HTTPException, Request +from fastapi.responses import StreamingResponse +from pydantic import BaseModel, Field + +from app.config import settings +from app.services.backtest import ( + BacktestConfig, + BacktestService, + VectorbtUnavailable, + is_available, +) + +router = APIRouter(prefix="/api/backtest", tags=["backtest"]) + +FACTOR_DEFAULT_DAYS = 180 +STRATEGY_DEFAULT_DAYS = 365 * 3 +BACKTEST_MAX_SERVER_DAYS = 186 +FACTOR_MAX_SYMBOLS = 1000 +BACKTEST_SERVER_GUARD_MESSAGE = ( + "当前服务器内存约 1.8GB,回测区间最多支持 6 个月;" + "更长周期容易触发 OOM,建议在 8GB 以上内存环境或本机运行。" +) + + +def _get_engine(request: Request): + """获取或创建 BacktestEngine (单例,PanelCache 跨请求生效)。""" + from app.backtest.engine import BacktestEngine + engine = getattr(request.app.state, "backtest_engine", None) + if engine is None: + engine = BacktestEngine(request.app.state.repo) + request.app.state.backtest_engine = engine + return engine + + +def _resolve_start(req: BaseModel, end: date, default_days: int) -> date: + """未传 start 使用默认区间;显式传 null/空值表示全部历史。""" + start = getattr(req, "start") + if start is not None: + return start + if "start" in req.model_fields_set: + return date(1900, 1, 1) + return end - timedelta(days=default_days) + + +def _guard_server_backtest_range(start: date, end: date): + if not settings.backtest_range_guard: + return + days = (end - start).days + 1 + if days > BACKTEST_MAX_SERVER_DAYS: + raise HTTPException(status_code=400, detail=BACKTEST_SERVER_GUARD_MESSAGE) + + +# ================================================================ +# 状态 +# ================================================================ + +@router.get("/status") +def status(): + """前端可用此接口判断回测页是否要灰显。""" + return {"available": True} + + +# ================================================================ +# 信号回测 (现有接口,保持不变) +# ================================================================ + +class BacktestRequest(BaseModel): + symbols: list[str] = Field(..., min_length=1) + start: date | None = None + end: date | None = None + entries: list[str] = [] + exits: list[str] = [] + stop_loss_pct: float | None = None + max_hold_days: int | None = None + fees_pct: float = 0.0002 + slippage_bps: float = 5 + matching: Literal["close_t", "open_t+1"] = "close_t" + + +@router.post("/run") +def run(req: BacktestRequest, request: Request): + """信号回测 — 现有接口,向后兼容。""" + repo = request.app.state.repo + svc = BacktestService(repo) + end = req.end or date.today() + start = req.start or (end - timedelta(days=365 * 3)) + + cfg = BacktestConfig( + symbols=req.symbols, + start=start, + end=end, + entries=req.entries, + exits=req.exits, + stop_loss_pct=req.stop_loss_pct, + max_hold_days=req.max_hold_days, + fees_pct=req.fees_pct, + slippage_bps=req.slippage_bps, + matching=req.matching, + ) + try: + result = svc.run(cfg) + except VectorbtUnavailable as e: + raise HTTPException(status_code=503, detail=str(e)) from e + return asdict(result) + + +# ================================================================ +# 因子回测 +# ================================================================ + +class FactorColumnsResponse(BaseModel): + columns: list[dict] + + +@router.get("/factor/columns") +def factor_columns(): + """返回可用的因子列列表。""" + from app.backtest.factor import FACTOR_COLUMNS + return {"columns": FACTOR_COLUMNS} + + +class FactorBacktestRequest(BaseModel): + factor_name: str + symbols: list[str] | None = None + start: date | None = None + end: date | None = None + n_groups: int = 5 + rebalance: Literal["daily", "weekly", "monthly"] = "monthly" + weight: Literal["equal", "factor_weight"] = "equal" + fees_pct: float = 0.0002 + slippage_bps: float = 5.0 + + +@router.post("/factor/run") +def factor_run(req: FactorBacktestRequest, request: Request): + """因子回测 — IC/IR 分析 + 分层回测。""" + from app.backtest.factor import FactorBacktestService, FactorConfig + + engine = _get_engine(request) + svc = FactorBacktestService(engine) + + end = req.end or date.today() + start = _resolve_start(req, end, STRATEGY_DEFAULT_DAYS) + _guard_server_backtest_range(start, end) + symbols = req.symbols if req.symbols else None + if symbols is not None and len(symbols) > FACTOR_MAX_SYMBOLS: + raise HTTPException( + status_code=400, + detail=f"指定标的最多支持 {FACTOR_MAX_SYMBOLS} 只,请缩小标的范围。", + ) + + cfg = FactorConfig( + factor_name=req.factor_name, + symbols=symbols, + start=start, + end=end, + n_groups=req.n_groups, + rebalance=req.rebalance, + weight=req.weight, + fees_pct=req.fees_pct, + slippage_bps=req.slippage_bps, + ) + result = svc.run(cfg) + return asdict(result) + + +# ================================================================ +# 策略回测 +# ================================================================ + +class StrategyBacktestRequest(BaseModel): + strategy_id: str + symbols: list[str] | None = None + start: date | None = None + end: date | None = None + params: dict | None = None + overrides: dict | None = None + matching: Literal["close_t", "open_t+1"] = "open_t+1" + fees_pct: float = 0.0002 + slippage_bps: float = 5.0 + max_positions: int = 10 + max_exposure_pct: float = 1.0 + initial_capital: float = 1_000_000.0 + position_sizing: Literal["equal", "score_weight"] = "equal" + mode: Literal["position", "full"] = "position" + holding_days: int = 5 + + +@router.post("/strategy/run") +def strategy_run(req: StrategyBacktestRequest, request: Request): + """策略回测 — 复用 StrategyDef 体系做全周期回测。""" + from app.backtest.strategy import StrategyBacktestService, StrategyBacktestConfig + + engine = _get_engine(request) + strategy_engine = request.app.state.strategy_engine + svc = StrategyBacktestService(engine, strategy_engine) + + end = req.end or date.today() + start = _resolve_start(req, end, FACTOR_DEFAULT_DAYS) + _guard_server_backtest_range(start, end) + + cfg = StrategyBacktestConfig( + strategy_id=req.strategy_id, + symbols=req.symbols if req.symbols else None, + start=start, + end=end, + params=req.params, + overrides=req.overrides, + matching=req.matching, + fees_pct=req.fees_pct, + slippage_bps=req.slippage_bps, + max_positions=req.max_positions, + max_exposure_pct=req.max_exposure_pct, + initial_capital=req.initial_capital, + position_sizing=req.position_sizing, + mode=req.mode, + holding_days=req.holding_days, + ) + result = svc.run(cfg) + return asdict(result) + + +# ── SSE 流式回测 (实时进度 + 可取消 + 支持重连) ─────────────────── + +import time +import hashlib + + +class _BacktestJob: + """单个回测任务的状态, 存模块级供重连使用。""" + __slots__ = ("key", "cancel_event", "progress", "result", "error", "done", "finish_ts") + + def __init__(self, key: str): + self.key = key + self.cancel_event = threading.Event() + self.progress: list[dict] = [] # 进度历史 (新连接可回放) + self.result = None # 完成后的结果 + self.error: str | None = None + self.done = False + self.finish_ts: float = 0.0 + + +# 模块级任务表: key -> _BacktestJob +_running_jobs: dict[str, _BacktestJob] = {} +_jobs_lock = threading.Lock() +_JOB_TTL = 300 # 完成后保留 5 分钟 + + +def _cleanup_stale_jobs(): + """清理过期任务 (完成超过 TTL 的)。""" + now = time.time() + stale = [k for k, j in _running_jobs.items() if j.done and now - j.finish_ts > _JOB_TTL] + for k in stale: + _running_jobs.pop(k, None) + + +def _make_job_key( + strategy_id: str, symbols: str | None, start: str | None, end: str | None, + matching: str, fees_pct: float, slippage_bps: float, + max_positions: int, max_exposure_pct: float, initial_capital: float, position_sizing: str, + params: str | None, overrides: str | None, + mode: str = "position", holding_days: int = 5, +) -> str: + raw = f"{strategy_id}|{symbols}|{start}|{end}|{matching}|{fees_pct}|{slippage_bps}|{max_positions}|{max_exposure_pct}|{initial_capital}|{position_sizing}|{params}|{overrides}|{mode}|{holding_days}" + return hashlib.md5(raw.encode()).hexdigest()[:12] + + +@router.get("/strategy/stream") +async def strategy_stream( + request: Request, + strategy_id: str, + symbols: str | None = None, + start: str | None = None, + end: str | None = None, + matching: str = "open_t+1", + fees_pct: float = 0.0002, + slippage_bps: float = 5.0, + max_positions: int = 10, + max_exposure_pct: float = 1.0, + initial_capital: float = 1_000_000.0, + position_sizing: str = "equal", + params: str | None = None, + overrides: str | None = None, + mode: str = "position", + holding_days: int = 5, +): + """SSE 流式策略回测: 实时推送进度, 完成后推送结果, 支持重连 (刷新/切页后恢复)。 + + - 相同参数的任务只启动一次, 多次连接订阅同一个任务 + - 断开连接不会取消任务 (除非显式调用 cancel) + - 结果保留 5 分钟供重连 + + 事件类型: + - progress: {day, total, date, equity} + - done: {result} (完整回测结果) + - error: {message} + """ + from app.backtest.strategy import StrategyBacktestService, StrategyBacktestConfig + + engine = _get_engine(request) + strategy_engine = request.app.state.strategy_engine + svc = StrategyBacktestService(engine, strategy_engine) + + end_date = date.fromisoformat(end) if end else date.today() + if start: + start_date = date.fromisoformat(start) + else: + # 空 start = 全部历史: 用本地最早日K日期, 查不到再回退到默认窗口 + earliest = request.app.state.repo.earliest_daily_date() + start_date = earliest or (end_date - timedelta(days=FACTOR_DEFAULT_DAYS)) + + # 服务端范围保护 + guard_violated = False + if settings.backtest_range_guard: + days = (end_date - start_date).days + 1 + if days > BACKTEST_MAX_SERVER_DAYS: + guard_violated = True + + job_key = _make_job_key( + strategy_id, symbols, start, end, + matching, fees_pct, slippage_bps, max_positions, max_exposure_pct, initial_capital, position_sizing, + params, overrides, + mode, holding_days, + ) + + _cleanup_stale_jobs() + + # 获取或创建任务 + with _jobs_lock: + job = _running_jobs.get(job_key) + if job is None: + job = _BacktestJob(job_key) + _running_jobs[job_key] = job + is_new = True + else: + is_new = False + + async def event_generator(): + # 范围保护: 直接报错 + if guard_violated: + yield f"event: error\ndata: {json.dumps({'message': BACKTEST_SERVER_GUARD_MESSAGE}, ensure_ascii=False)}\n\n" + return + + # 如果是新任务, 启动回测线程 + if is_new and not job.done: + cfg = StrategyBacktestConfig( + strategy_id=strategy_id, + symbols=[s.strip() for s in symbols.split(",") if s.strip()] if symbols else None, + start=start_date, + end=end_date, + params=json.loads(params) if params else None, + overrides=json.loads(overrides) if overrides else None, + matching=matching, + fees_pct=fees_pct, + slippage_bps=slippage_bps, + max_positions=int(max_positions), + max_exposure_pct=float(max_exposure_pct), + initial_capital=float(initial_capital), + position_sizing=position_sizing, + mode=mode, + holding_days=int(holding_days), + ) + + def _run_backtest(): + try: + result = svc.run(cfg, lambda d: job.progress.append(d), job.cancel_event) + job.result = result + job.done = True + job.finish_ts = time.time() + except Exception as e: + job.error = str(e) + job.done = True + job.finish_ts = time.time() + + # 启动后台线程 (不阻塞事件循环) + threading.Thread(target=_run_backtest, daemon=True).start() + + # 订阅进度: 用读指针读 job.progress 列表 (多连接互不干扰) + cursor = 0 + tick = 0 + + try: + while True: + # 已完成: 推送最终结果/错误并退出 + if job.done: + if job.error: + yield f"event: error\ndata: {json.dumps({'message': job.error}, ensure_ascii=False)}\n\n" + elif job.result is not None: + r = job.result + if hasattr(r, "error") and r.error == "cancelled": + yield f"event: error\ndata: {json.dumps({'message': '回测已取消'}, ensure_ascii=False)}\n\n" + elif hasattr(r, "error") and r.error: + yield f"event: error\ndata: {json.dumps({'message': r.error}, ensure_ascii=False)}\n\n" + else: + yield f"event: done\ndata: {json.dumps(asdict(r), ensure_ascii=False, default=str)}\n\n" + return + + # 断开检测: 每 4 轮检查一次 (降低 GIL 抢占频率) + tick += 1 + if tick % 4 == 0 and await request.is_disconnected(): + break + + # 推送新进度 (从 cursor 开始读) + prog_list = job.progress + while cursor < len(prog_list): + msg = prog_list[cursor] + cursor += 1 + yield f"event: progress\ndata: {json.dumps(msg, ensure_ascii=False, default=str)}\n\n" + + await asyncio.sleep(0.5) + + except asyncio.CancelledError: + raise + + return StreamingResponse(event_generator(), media_type="text/event-stream") + + +@router.post("/strategy/cancel") +async def strategy_cancel(request: Request): + """取消正在运行的回测任务 (前端传 query string, 后端算 job_key)。""" + body = await request.json() + qs = body.get("qs", "") + # 解析 qs 得到参数 + from urllib.parse import parse_qs + p = parse_qs(qs) + def _get(key: str, default: str = "") -> str: + return p.get(key, [default])[0] + job_key = _make_job_key( + _get("strategy_id"), + _get("symbols") or None, + _get("start") or None, + _get("end") or None, + _get("matching", "open_t+1"), + float(_get("fees_pct", "0.0002")), + float(_get("slippage_bps", "5")), + int(_get("max_positions", "10")), + float(_get("max_exposure_pct", "1")), + float(_get("initial_capital", "1000000")), + _get("position_sizing", "equal"), + _get("params") or None, + _get("overrides") or None, + _get("mode", "position"), + int(_get("holding_days", "5")), + ) + job = _running_jobs.get(job_key) + if job and not job.done: + job.cancel_event.set() + return {"ok": True} + return {"ok": False, "message": "任务不存在或已完成"} + diff --git a/backend/app/api/data.py b/backend/app/api/data.py new file mode 100644 index 0000000..b1feec7 --- /dev/null +++ b/backend/app/api/data.py @@ -0,0 +1,710 @@ +"""数据画像 API —— 让前端知道"我们本地有什么数据"。""" +from __future__ import annotations + +import logging +import os +import threading +import time +from datetime import datetime, timezone +from pathlib import Path +from typing import Any, Callable + +from fastapi import APIRouter, Request + +from app.indicators.pipeline import ENRICHED_COLUMNS + +logger = logging.getLogger(__name__) + +router = APIRouter(prefix="/api/data", tags=["data"]) + +# ===== 缓存:storage(文件扫描) + 每张表 aggregate 各自缓存 ===== +# 同步期间前端 2s 轮一次 status,每张表 aggregate 全表 count + min/max + distinct +# 太重,加 TTL + 事件失效。stage 写完只清对应那张表的缓存。 + +_TABLE_TTL = 30.0 # 兜底 TTL,即使没人调 invalidate 也会过期 +_TABLE_TTL_LARGE = 120.0 # 大表(分钟K等)单独 TTL,避免多分区聚合反复重算 +_STORAGE_TTL = 60.0 # storage 文件扫描独立 TTL,stage 写完不触发重算 + +# 聚合慢的大表(分区数多、行数多),使用更长的 TTL +_LARGE_TABLES = {"minute"} + +_storage_cache: dict[str, Any] | None = None +_storage_cache_ts: float = 0.0 +_storage_lock = threading.Lock() + +_table_cache: dict[str, dict | None] = { + "daily": None, + "enriched": None, + "index_daily": None, + "index_enriched": None, + "index_instruments": None, + "minute": None, + "adj_factor": None, + "instruments": None, + "financials": None, +} +_table_cache_ts: dict[str, float] = {k: 0.0 for k in _table_cache} +_table_cache_lock = threading.Lock() + +_last_finished_cache: dict[str, str | None] | None = None +_last_finished_lock = threading.Lock() + + +def invalidate_data_cache(table: str | None = None) -> None: + """数据写入/清除后调用。 + + table=None 时清所有表 cache + storage(粗粒度,用于 pipeline 完成/clear); + 指定 table 时只清那张表,不影响 storage(细粒度,用于单 stage 写完)。 + """ + with _table_cache_lock: + if table is None: + global _storage_cache, _storage_cache_ts, _last_finished_cache + _storage_cache = None + _storage_cache_ts = 0.0 + _last_finished_cache = None + for k in _table_cache: + _table_cache[k] = None + _table_cache_ts[k] = 0.0 + elif table in _table_cache: + _table_cache[table] = None + _table_cache_ts[table] = 0.0 + + +def invalidate_storage_cache() -> None: + """向后兼容入口 — 清全部缓存。新代码请用 invalidate_data_cache(table)。""" + invalidate_data_cache(None) + + +def _get_table_stats(name: str, fetch: Callable[[], dict | None]) -> dict | None: + """走 TTL+事件 双重缓存。fetch 在锁外执行避免阻塞别的请求。""" + ttl = _TABLE_TTL_LARGE if name in _LARGE_TABLES else _TABLE_TTL + now = time.time() + with _table_cache_lock: + cached = _table_cache.get(name) + cached_ts = _table_cache_ts.get(name, 0.0) + if cached is not None and (now - cached_ts) < ttl: + return cached + + fresh = fetch() + + with _table_cache_lock: + _table_cache[name] = fresh + _table_cache_ts[name] = now + return fresh + + +def _safe_aggregate(repo, view: str) -> dict | None: + """聚合视图基础统计;视图不存在或为空时返 None。""" + try: + row = repo.execute_one( + f"""SELECT count(*) AS rows, + min(date) AS earliest, + max(date) AS latest, + count(DISTINCT symbol) AS symbols, + count(DISTINCT date) AS trading_days + FROM {view}""" + ) + except Exception as e: # noqa: BLE001 + logger.debug("aggregate %s failed: %s", view, e) + return None + if not row or not row[0]: + return None + return { + "rows": int(row[0]), + "earliest_date": str(row[1]) if row[1] else None, + "latest_date": str(row[2]) if row[2] else None, + "symbols_covered": int(row[3] or 0), + "trading_days": int(row[4] or 0), + } + + +def _safe_aggregate_daily(repo, view: str = "kline_daily") -> dict | None: + """日K轻量统计 — 零数据扫描。 + + 从分区目录名获取日期范围和交易日数,不读任何 parquet。 + 标的数从 instruments 小表获取(~5000行,毫秒级)。 + """ + daily_dir = repo.store.data_dir / "kline_daily" + if not daily_dir.exists(): + return None + dates: list[str] = [] + for d in daily_dir.iterdir(): + if d.is_dir() and d.name.startswith("date="): + dates.append(d.name[5:]) + if not dates: + return None + dates.sort() + + symbols = _count_instruments_symbols(repo) + + return { + "rows": 0, + "earliest_date": dates[0], + "latest_date": dates[-1], + "symbols_covered": symbols, + "trading_days": len(dates), + } + + +def _safe_aggregate_enriched(repo) -> dict | None: + """Enriched 轻量统计 — 零数据扫描。 + + 字段数从 DESCRIBE 读 schema(不碰数据),毫秒级。 + 日期范围从分区目录名获取(同 minute 策略),不读任何 parquet。 + 标的数从 instruments 小表取。 + """ + # 字段数:读 schema,不碰数据 + fields = 0 + try: + cols = repo.execute_all("DESCRIBE kline_enriched") + fields = len(cols) + except Exception: # noqa: BLE001 + pass + + # 日期范围:从分区目录名获取,不扫数据 + enriched_dir = repo.store.data_dir / "kline_daily_enriched" + if not enriched_dir.exists(): + return None + dates: list[str] = [] + for d in enriched_dir.iterdir(): + if d.is_dir() and d.name.startswith("date="): + dates.append(d.name[5:]) + if not dates: + return None + dates.sort() + + symbols = _count_instruments_symbols(repo) + + return { + "rows": 0, + "fields": fields, + "earliest_date": dates[0], + "latest_date": dates[-1], + "symbols_covered": symbols, + "trading_days": len(dates), + } + + +def _count_instruments_symbols(repo) -> int: + """从 instruments 小表取标的数(~5000行,毫秒级)。""" + try: + sym_row = repo.execute_one( + "SELECT count(DISTINCT symbol) FROM instruments" + ) + if sym_row and sym_row[0]: + return int(sym_row[0]) + except Exception: # noqa: BLE001 + pass + return 0 + + +def _safe_aggregate_instruments(repo) -> dict | None: + """instruments 视图统计(无 date 列,用 as_of)。""" + try: + row = repo.execute_one( + """SELECT count(*) AS rows, + count(DISTINCT symbol) AS symbols, + max(as_of) AS latest_as_of, + count_if(name IS NOT NULL AND name != '') AS named + FROM instruments""" + ) + except Exception as e: # noqa: BLE001 + logger.debug("aggregate instruments failed: %s", e) + return None + if not row or not row[0]: + return None + return { + "rows": int(row[0]), + "symbols_covered": int(row[1] or 0), + "latest_as_of": str(row[2]) if row[2] else None, + "named": int(row[3] or 0), + } + + +def _safe_aggregate_index_daily(repo) -> dict | None: + """指数日K统计。指数数据量较小,直接读取 parquet 元数据统计真实行数。""" + return _safe_aggregate(repo, "kline_index_daily") + + +def _safe_aggregate_index_enriched(repo) -> dict | None: + """指数 enriched 统计。指数数据量较小,直接读取 parquet 元数据统计真实行数。""" + fields = 0 + try: + cols = repo.execute_all("DESCRIBE kline_index_enriched") + fields = len(cols) + except Exception: # noqa: BLE001 + pass + stats = _safe_aggregate(repo, "kline_index_enriched") + if not stats: + return None + return {**stats, "fields": fields} + + +def _safe_aggregate_index_instruments(repo) -> dict | None: + """指数 instruments 视图统计。""" + try: + row = repo.execute_one( + """SELECT count(*) AS rows, + count(DISTINCT symbol) AS symbols, + count_if(name IS NOT NULL AND name != '') AS named + FROM instruments_index""" + ) + except Exception as e: # noqa: BLE001 + logger.debug("aggregate instruments_index failed: %s", e) + return None + if not row or not row[0]: + return None + return { + "rows": int(row[0]), + "symbols_covered": int(row[1] or 0), + "latest_as_of": None, + "named": int(row[2] or 0), + } + + +def _safe_aggregate_adj_factor(repo) -> dict | None: + """adj_factor 视图统计,日期范围对齐日 K 覆盖区间。""" + try: + # 取日 K 的日期范围作为过滤条件 + dr = repo.execute_one( + "SELECT min(date), max(date) FROM kline_daily" + ) + if not dr or not dr[0]: + return None + d_min, d_max = dr[0], dr[1] + row = repo.execute_one( + """SELECT count(*) AS rows, + count(DISTINCT symbol) AS symbols, + count(DISTINCT trade_date) AS trading_days + FROM adj_factor + WHERE trade_date BETWEEN ? AND ?""", + [str(d_min), str(d_max)], + ) + if not row or not row[0]: + return None + return { + "rows": int(row[0]), + "symbols_covered": int(row[1]) if isinstance(row[1], (int, float)) else 0, + "earliest_date": str(d_min), + "latest_date": str(d_max), + "trading_days": int(row[2] or 0), + } + except Exception as e: # noqa: BLE001 + logger.debug("aggregate adj_factor failed: %s", e) + return None + + +def _safe_aggregate_minute(repo) -> dict | None: + """kline_minute 统计 — 从分区目录名获取交易日数,跳过全表扫描。 + + 分钟 K 按 date=YYYY-MM-DD 分区存储,直接数目录即可, + 无需 count(*) / count(DISTINCT ...) 等昂贵查询。 + """ + minute_dir = repo.store.data_dir / "kline_minute" + if not minute_dir.exists(): + return None + + # 从 date=YYYY-MM-DD 目录名提取交易日 + dates: list[str] = [] + for d in minute_dir.iterdir(): + if d.is_dir() and d.name.startswith("date="): + dates.append(d.name[5:]) + + if not dates: + return None + + dates.sort() + return { + "rows": 0, # 不再查询行数 + "earliest_date": dates[0], + "latest_date": dates[-1], + "symbols_covered": 0, # 不再查询标的数 + "trading_days": len(dates), + } + + +def _safe_aggregate_financials(repo) -> dict | None: + """财务数据统计 — 检查各表文件是否存在及行数。""" + data_dir = repo.store.data_dir + tables_info: dict[str, dict] = {} + total_rows = 0 + + for table in ("metrics", "income", "balance_sheet", "cash_flow"): + path = data_dir / "financials" / table / "part.parquet" + if path.exists(): + try: + import polars as pl + df = pl.read_parquet(path, columns=["symbol"]) + rows = len(df) + symbols = df["symbol"].n_unique() if not df.is_empty() else 0 + tables_info[table] = {"rows": rows, "symbols": symbols} + total_rows += rows + except Exception: + tables_info[table] = {"rows": 0, "symbols": 0} + else: + tables_info[table] = {"rows": 0, "symbols": 0} + + if total_rows == 0: + return None + + return { + "rows": total_rows, + "tables": tables_info, + } + + +def _scan_dir_stats(dirpath: Path) -> tuple[int, float]: + """单次遍历统计目录下文件数和总大小(MB)。比 rglob+stat 快很多。""" + if not dirpath.exists(): + return 0, 0.0 + count = 0 + total = 0 + for entry in os.scandir(dirpath): + if entry.is_dir(follow_symlinks=False): + c, s = _scan_dir_recursive(entry) + count += c + total += s + elif entry.is_file(follow_symlinks=False): + try: + total += entry.stat().st_size + except OSError: + pass + count += 1 + return count, round(total / 1048576, 2) + + +def _scan_dir_recursive(entry: os.DirEntry) -> tuple[int, int]: + """递归统计一个 DirEntry 下的文件数和总字节数。""" + count = 0 + total = 0 + try: + for sub in os.scandir(entry.path): + if sub.is_dir(follow_symlinks=False): + c, s = _scan_dir_recursive(sub) + count += c + total += s + elif sub.is_file(follow_symlinks=False): + try: + total += sub.stat().st_size + except OSError: + pass + count += 1 + except PermissionError: + pass + return count, total + + +def _compute_storage(data_dir: Path) -> dict: + """单次遍历计算 storage 统计,避免多次 rglob。""" + import os + + # 只统计关心的子目录 + subdirs = { + "daily": data_dir / "kline_daily", + "enriched": data_dir / "kline_daily_enriched", + "index_daily": data_dir / "kline_index_daily", + "index_enriched": data_dir / "kline_index_enriched", + "index_instruments": data_dir / "instruments_index", + "minute": data_dir / "kline_minute", + "adj_factor": data_dir / "adj_factor", + "instruments": data_dir / "instruments", + "ext_data": data_dir / "ext_data", + } + stats = {} + total_size = 0 + for key, d in subdirs.items(): + fc, sz = _scan_dir_stats(d) + total_size += sz + stats[f"{key}_files"] = fc + stats[f"{key}_size_mb"] = sz + + # total: 再加上其他零散文件(pools, financials, capabilities.json 等) + other_dirs = ["pools", "financials", "backtest_results", "screener_results", "ai_cache"] + for name in other_dirs: + d = data_dir / name + if d.exists(): + _, s = _scan_dir_stats(d) + total_size += s + + # financials 单独统计 + fin_dir = data_dir / "financials" + if fin_dir.exists(): + fc, sz = _scan_dir_stats(fin_dir) + stats["financials_files"] = fc + stats["financials_size_mb"] = sz + total_size += sz + for name in other_dirs: + d = data_dir / name + if d.exists(): + _, s = _scan_dir_stats(d) + total_size += s + # 根目录散文件 + for entry in os.scandir(data_dir): + if entry.is_file(follow_symlinks=False): + try: + total_size += entry.stat().st_size / 1048576 + except OSError: + pass + stats["total_size_mb"] = round(total_size, 2) + return stats + + +def _next_cron_run(scheduler, job_id: str) -> str | None: + """读 APScheduler 下次执行时间。""" + if not scheduler: + return None + try: + job = scheduler.get_job(job_id) + if job and job.next_run_time: + return job.next_run_time.isoformat(timespec="seconds") + except Exception: # noqa: BLE001 + pass + return None + + +def _get_storage(data_dir: Path) -> dict: + """返回缓存的 storage 统计;走独立 TTL,stage 写完不触发重算。""" + global _storage_cache, _storage_cache_ts + now = time.time() + with _storage_lock: + if _storage_cache is not None and (now - _storage_cache_ts) < _STORAGE_TTL: + return _storage_cache + fresh = _compute_storage(data_dir) + with _storage_lock: + _storage_cache = fresh + _storage_cache_ts = now + return fresh + + +def _last_finished(job_label: str) -> str | None: + """从 JobStore 读最近一次该类型任务的完成时间(缓存到 pipeline 终态失效)。""" + global _last_finished_cache + with _last_finished_lock: + if _last_finished_cache is not None: + return _last_finished_cache.get(job_label) + + from app.services.pipeline_jobs import job_store + jobs = job_store.list_recent(limit=50) + cache: dict[str, str | None] = {} + for j in jobs: + if j["status"] not in ("succeeded", "failed"): + continue + if "instruments_rows" in (j.get("result") or {}) and "instruments" not in cache: + cache["instruments"] = j["finished_at"] + if "daily_days" in (j.get("result") or {}) and "pipeline" not in cache: + cache["pipeline"] = j["finished_at"] + with _last_finished_lock: + _last_finished_cache = cache + return cache.get(job_label) + + +@router.get("/status") +def status(request: Request) -> dict: + repo = request.app.state.repo + scheduler = getattr(request.app.state, "scheduler", None) + data_dir = repo.store.data_dir + + return { + "daily": _get_table_stats("daily", lambda: _safe_aggregate_daily(repo)), + "enriched": _get_table_stats("enriched", lambda: _safe_aggregate_enriched(repo)), + "index_daily": _get_table_stats("index_daily", lambda: _safe_aggregate_index_daily(repo)), + "index_enriched": _get_table_stats("index_enriched", lambda: _safe_aggregate_index_enriched(repo)), + "index_instruments": _get_table_stats("index_instruments", lambda: _safe_aggregate_index_instruments(repo)), + "minute": _get_table_stats("minute", lambda: _safe_aggregate_minute(repo)), + "adj_factor": _get_table_stats("adj_factor", lambda: _safe_aggregate_adj_factor(repo)), + "instruments": _get_table_stats("instruments", lambda: _safe_aggregate_instruments(repo)), + "financials": _get_table_stats("financials", lambda: _safe_aggregate_financials(repo)), + + # 文件层面信息(缓存) + "storage": _get_storage(data_dir), + + # 调度 + "next_instruments_run": _next_cron_run(scheduler, "pre_market_instruments"), + "next_pipeline_run": _next_cron_run(scheduler, "daily_pipeline"), + "last_instruments_run": _last_finished("instruments"), + "last_pipeline_run": _last_finished("pipeline"), + "checked_at": datetime.now(timezone.utc).isoformat(timespec="seconds").replace("+00:00", "Z"), + } + + +@router.post("/clear") +def clear_data(request: Request): + """清除所有本地 Parquet 数据(保留 capabilities.json 和目录结构)。""" + import shutil + + repo = request.app.state.repo + data_dir = repo.store.data_dir + deleted = 0 + + for sub in ( + "kline_daily", "kline_daily_enriched", "kline_index_daily", "kline_index_enriched", "kline_minute", + "adj_factor", "instruments", "instruments_index", "pools", "financials", + "backtest_results", "screener_results", "ai_cache", + ): + d = data_dir / sub + if d.exists(): + # 先删所有 parquet 文件 + for f in d.rglob("*.parquet"): + f.unlink() + deleted += 1 + # 再删除空的日期分区子目录(date=YYYY-MM-DD 等) + for child in list(d.iterdir()): + if child.is_dir(): + shutil.rmtree(child, ignore_errors=True) + + # 清除同步历史(内存 + 磁盘 job_store/ 文件夹) + from app.services.pipeline_jobs import job_store + job_store.clear() + + # 清除财务数据 + fin_dir = data_dir / "financials" + for sub in ("metrics", "income", "balance_sheet", "cash_flow"): + fp = fin_dir / sub / "part.parquet" + if fp.exists(): + fp.unlink() + deleted += 1 + + # 清除 Polars 缓存 + repo.refresh_cache() + + # 刷新 DuckDB 视图(空 parquet 目录也需要重新挂载) + d = data_dir.as_posix() + for name, path in { + "kline_daily": f"{d}/kline_daily/**/*.parquet", + "kline_enriched": f"{d}/kline_daily_enriched/**/*.parquet", + "kline_index_daily": f"{d}/kline_index_daily/**/*.parquet", + "kline_index_enriched": f"{d}/kline_index_enriched/**/*.parquet", + "kline_minute": f"{d}/kline_minute/**/*.parquet", + "adj_factor": f"{d}/adj_factor/**/*.parquet", + "instruments": f"{d}/instruments/**/*.parquet", + "instruments_index": f"{d}/instruments_index/**/*.parquet", + }.items(): + try: + repo.db.execute( + f"CREATE OR REPLACE VIEW {name} AS " + f"SELECT * FROM read_parquet('{path}', union_by_name=true)" + ) + except Exception: + pass + + logger.info("数据已清除: 删除 %d 个 parquet 文件", deleted) + invalidate_data_cache(None) + return {"deleted_files": deleted} + + +# 各表字段说明 +_TABLE_FIELD_DESC: dict[str, dict[str, str]] = { + "kline_daily": { + "symbol": "股票代码", + "date": "交易日期", + "open": "开盘价", + "high": "最高价", + "low": "最低价", + "close": "收盘价", + "volume": "成交量", + "amount": "成交额", + }, + "kline_enriched": ENRICHED_COLUMNS, + "kline_index_daily": { + "symbol": "指数代码", + "date": "交易日期", + "open": "开盘点位", + "high": "最高点位", + "low": "最低点位", + "close": "收盘点位", + "volume": "成交量", + "amount": "成交额", + }, + "kline_index_enriched": ENRICHED_COLUMNS, + "kline_minute": { + "symbol": "股票代码", + "datetime": "分钟时间戳", + "open": "开盘价", + "high": "最高价", + "low": "最低价", + "close": "收盘价", + "volume": "成交量", + "amount": "成交额", + }, + "adj_factor": { + "symbol": "股票代码", + "timestamp": "除权除息时间戳(ms)", + "trade_date": "除权除息日", + "ex_factor": "复权因子", + }, + "instruments": { + "symbol": "股票代码", + "name": "股票名称", + "code": "股票编码(纯数字)", + "exchange": "交易所(SH/SZ/BJ)", + "region": "地区", + "type": "证券类型", + "listing_date": "上市日期", + "total_shares": "总股本", + "float_shares": "流通股本", + "tick_size": "最小价格变动单位", + "limit_up": "涨停限制(%)", + "limit_down": "跌停限制(%)", + "as_of": "快照日期", + }, + "instruments_index": { + "symbol": "指数代码", + "name": "指数名称", + "code": "指数编码(纯数字)", + "asset_type": "资产类型(index)", + }, +} + +# view 名 → DuckDB 视图名 +_SCHEMA_VIEWS: dict[str, str] = { + "daily": "kline_daily", + "enriched": "kline_enriched", + "index_daily": "kline_index_daily", + "index_enriched": "kline_index_enriched", + "index_instruments": "instruments_index", + "minute": "kline_minute", + "adj_factor": "adj_factor", + "instruments": "instruments", +} + + +@router.get("/schema/{table}") +def table_schema(request: Request, table: str) -> list[dict]: + """返回指定表的字段名、类型和中文说明。 + + 优先从 DuckDB DESCRIBE 读取(有数据时含精确类型); + 视图不存在(无数据)时回退到 _TABLE_FIELD_DESC 静态定义。 + """ + view = _SCHEMA_VIEWS.get(table) + if not view: + return [] + desc_map = _TABLE_FIELD_DESC.get(view, {}) + repo = request.app.state.repo + fields: list[dict] = [] + try: + cols = repo.execute_all(f"DESCRIBE {view}") + for col in cols: + name = col[0] + dtype = col[1] + fields.append({ + "name": name, + "type": dtype, + "desc": desc_map.get(name, ""), + }) + except Exception: # noqa: BLE001 + # 视图不存在(本地无数据),用静态字段定义兜底 + if desc_map: + for name, desc in desc_map.items(): + fields.append({"name": name, "type": "—", "desc": desc}) + return fields + + +@router.get("/version") +def get_version(request: Request) -> dict: + """返回当前项目版本号(读取项目根目录 VERSION 文件)。""" + from app.config import settings + version_file = Path(settings.data_dir).parent / "VERSION" + version = "v0.0.0" + if version_file.exists(): + version = version_file.read_text(encoding="utf-8").strip() or version + return {"version": version} diff --git a/backend/app/api/ext_data.py b/backend/app/api/ext_data.py new file mode 100644 index 0000000..1d4ec84 --- /dev/null +++ b/backend/app/api/ext_data.py @@ -0,0 +1,825 @@ +"""扩展数据 API — CRUD + 文件上传 + JSON 写入 + 定时拉取 + schema 发现。""" +from __future__ import annotations + +import json +import logging +import math +import shutil +import tempfile +from datetime import date, datetime +from pathlib import Path +from typing import Literal + +import polars as pl +from fastapi import APIRouter, File, HTTPException, Query, Request, UploadFile +from pydantic import BaseModel, Field + +from app.services.ext_data import ( + ExtConfig, + ExtConfigStore, + ExtField, + PullConfig, + fix_symbol_format, + normalize_symbol, + parse_upload_file, + write_ext_parquet, + rows_to_parquet, +) +from app.services.ext_pull import fetch_and_ingest, pull_scheduler + +logger = logging.getLogger(__name__) +router = APIRouter(prefix="/api/ext-data", tags=["ext-data"]) + + +# --------------------------------------------------------------------------- +# Pydantic 模型 +# --------------------------------------------------------------------------- + +class FieldDef(BaseModel): + name: str + dtype: str = "string" # string | int | float | bool + label: str = "" + + +class CreateExtReq(BaseModel): + id: str = Field(..., min_length=1, max_length=64, pattern=r"^[a-zA-Z0-9_]+$") + label: str = Field(..., min_length=1, max_length=64) + mode: Literal["snapshot", "timeseries"] + fields: list[FieldDef] = Field(..., min_length=1) + description: str = "" + symbol_map: dict = {} # {"type": "mapped", "col": "..."} 或 {"type": "computed", "from": "code", "method": "append_exchange"} + code_map: dict = {} # {"type": "mapped", "col": "..."} 或 {"type": "computed", "from": "symbol", "method": "strip_exchange"} + + +class UpdateExtReq(BaseModel): + label: str | None = None + fields: list[FieldDef] | None = None + description: str | None = None + symbol_map: dict | None = None + code_map: dict | None = None + + +class IngestReq(BaseModel): + """JSON 批量写入请求。""" + date: str | None = None # YYYY-MM-DD,不传默认今天 + rows: list[dict] = Field(..., min_length=1) + + +class PullConfigReq(BaseModel): + """定时拉取配置请求。""" + url: str = Field(..., min_length=1) + method: str = "GET" + headers: dict[str, str] | None = None + body: str | None = None + response_path: str = "" # dot-path to rows array + field_map: dict[str, str] | None = None # external → internal field name + schedule_minutes: int = Field(1440, ge=1) + enabled: bool = False + + +# --------------------------------------------------------------------------- +# 辅助 +# --------------------------------------------------------------------------- + +def _store(request: Request) -> ExtConfigStore: + return ExtConfigStore(request.app.state.repo.store.data_dir) + + +def _data_dir(request: Request) -> Path: + return request.app.state.repo.store.data_dir + + +# --------------------------------------------------------------------------- +# CRUD +# --------------------------------------------------------------------------- + +def _apply_mapping(df: pl.DataFrame, config: ExtConfig, data_dir: Path) -> pl.DataFrame: + """根据 config 的 symbol_map / code_map 自动生成 symbol 和 code 列。 + + 执行顺序:先 mapped(从文件列复制),再 computed(从已生成的列计算)。 + """ + sm = config.symbol_map or {} + cm = config.code_map or {} + + # --- 第一步:mapped 类型,直接从文件列映射 --- + if sm.get("type") == "mapped" and sm["col"] in df.columns: + df = df.with_columns(df[sm["col"]].cast(pl.Utf8).alias("symbol")) + + if cm.get("type") == "mapped" and cm["col"] in df.columns: + df = df.with_columns(df[cm["col"]].cast(pl.Utf8).alias("code")) + + # --- 第二步:computed 类型,从已生成的列计算 --- + if "symbol" not in df.columns and sm.get("type") == "computed": + if sm.get("from") == "code" and "code" in df.columns: + # code → symbol: 000001 → 000001.SZ + from app.services.ext_data import build_code_lookup + lookup = build_code_lookup(data_dir) + df = df.with_columns(normalize_symbol(df["code"].cast(pl.Utf8), lookup).alias("symbol")) + + if "code" not in df.columns and cm.get("type") == "computed": + if cm.get("from") == "symbol" and "symbol" in df.columns: + # symbol → code: 000001.SZ → 000001 + df = df.with_columns( + df["symbol"].cast(pl.Utf8).str.split(".").list.first().alias("code") + ) + + # --- 兜底:如果只有一个,自动生成另一个 --- + if "symbol" in df.columns and "code" not in df.columns: + df = df.with_columns( + df["symbol"].cast(pl.Utf8).str.split(".").list.first().alias("code") + ) + elif "code" in df.columns and "symbol" not in df.columns: + from app.services.ext_data import build_code_lookup + lookup = build_code_lookup(data_dir) + df = df.with_columns(normalize_symbol(df["code"].cast(pl.Utf8), lookup).alias("symbol")) + + # 标准化 symbol 列 + if "symbol" in df.columns: + from app.services.ext_data import build_code_lookup + lookup = build_code_lookup(data_dir) + df = df.with_columns(normalize_symbol(df["symbol"].cast(pl.Utf8), lookup)) + + return df + + +def _clean_col_names(df: pl.DataFrame) -> pl.DataFrame: + """清洗列名:去掉所有 (...) 及其内容,避免时间戳导致列名不稳定。""" + import re + renames = {col: re.sub(r"\([^)]*\)", "", col).strip() for col in df.columns} + # 去重:如果清洗后重名,加序号后缀 + seen: dict[str, int] = {} + final = {} + for old, new in renames.items(): + if new in seen: + seen[new] += 1 + final[old] = f"{new}_{seen[new]}" + else: + seen[new] = 0 + final[old] = new + return df.rename(final) + + +def _ext_data_dir(config: ExtConfig, data_dir: Path) -> Path: + """返回扩展数据的数据目录。 + + - snapshot: data/ext_data/{id}/(part.parquet 与 config.json 同级) + - timeseries: data/ext_data/{id}/timeseries/ + """ + cfg_dir = data_dir / "ext_data" / config.id + if config.mode == "timeseries": + return cfg_dir / "timeseries" + return cfg_dir + + +def _parquet_glob(config: ExtConfig, data_dir: Path) -> str: + """返回该扩展配置下所有 parquet 文件的 glob 模式。 + + snapshot: 'data/ext_data/{id}/*.parquet'(只有 part.parquet) + timeseries: 'data/ext_data/{id}/timeseries/**/*.parquet' + """ + cfg_dir = data_dir / "ext_data" / config.id + if config.mode == "snapshot": + return str(cfg_dir / "*.parquet") + return str(cfg_dir / "timeseries" / "**" / "*.parquet") + + +def _safe_json_value(value): + if isinstance(value, float) and not math.isfinite(value): + return None + if isinstance(value, (date, datetime)): + return value.isoformat() + return value + + +def _read_ext_dataframe( + config: ExtConfig, + data_dir: Path, + snapshot_date: str | None = None, +) -> tuple[pl.DataFrame, str | None]: + cfg_dir = data_dir / "ext_data" / config.id + + if config.mode == "snapshot": + path = cfg_dir / "part.parquet" + if not path.exists(): + return pl.DataFrame(), None + return pl.read_parquet(path), _latest_sync_date(config, data_dir) + + base = cfg_dir / "timeseries" + if not base.exists(): + return pl.DataFrame(), None + + if snapshot_date: + path = base / f"date={snapshot_date}" / "part.parquet" + if not path.exists(): + return pl.DataFrame(), snapshot_date + return pl.read_parquet(path), snapshot_date + + partitions = sorted( + d for d in base.iterdir() + if d.is_dir() and d.name.startswith("date=") and (d / "part.parquet").exists() + ) + if not partitions: + return pl.DataFrame(), None + + latest = partitions[-1] + latest_date = latest.name[5:] + return pl.read_parquet(latest / "part.parquet"), latest_date + + +def _with_instrument_name(df: pl.DataFrame, data_dir: Path) -> pl.DataFrame: + if df.is_empty() or "symbol" not in df.columns or "name" in df.columns: + return df + path = data_dir / "instruments" / "instruments.parquet" + if not path.exists(): + return df + try: + inst = pl.read_parquet(path) + if "symbol" in inst.columns and "name" in inst.columns: + inst = inst.select(["symbol", "name"]).unique(subset=["symbol"], keep="last") + return df.join(inst, on="symbol", how="left") + except Exception: + return df + return df + + +def _latest_sync_date(config: ExtConfig, data_dir: Path) -> str | None: + """扫描数据文件,返回该扩展配置的最新同步时间(含时分秒)。 + + - snapshot: 直接取 ext_data/{id}/part.parquet 的 mtime + - timeseries: 扫描 ext_data/{id}/timeseries/date=xxx 分区目录 + """ + from datetime import datetime + + if config.mode == "snapshot": + # 快照: part.parquet 与 config.json 同级 + p = data_dir / "ext_data" / config.id / "part.parquet" + if p.exists(): + ts = datetime.fromtimestamp(p.stat().st_mtime).strftime("%Y-%m-%d %H:%M:%S") + return ts + # 兼容旧路径 + old = data_dir / "instruments_ext" + if old.exists(): + return _latest_sync_from_partitions(old) + return None + + # 时序: 扫描 timeseries/date=xxx + base = _ext_data_dir(config, data_dir) + if not base.exists(): + # 兼容旧路径 + base = data_dir / "kline_ext" + if not base.exists(): + return None + return _latest_sync_from_partitions(base) + + +def _latest_sync_from_partitions(base: Path) -> str | None: + """从 date=xxx 分区目录中找到最新分区的修改时间。""" + from datetime import datetime + latest_ts: float = 0 + latest_date: str | None = None + for d in base.iterdir(): + if d.is_dir() and d.name.startswith("date="): + for f in d.glob("*.parquet"): + mtime = f.stat().st_mtime + if mtime > latest_ts: + latest_ts = mtime + latest_date = d.name[5:] + if latest_date and latest_ts > 0: + ts = datetime.fromtimestamp(latest_ts).strftime("%H:%M:%S") + return f"{latest_date} {ts}" + return latest_date + + +def _date_range(config: ExtConfig, data_dir: Path) -> list[str] | None: + """返回时序型扩展数据的日期范围 [最早, 最新]。""" + if config.mode != "timeseries": + return None + base = _ext_data_dir(config, data_dir) + if not base.exists(): + # 兼容旧路径 + base = data_dir / "kline_ext" + if not base.exists(): + return None + dates: list[str] = [] + for d in base.iterdir(): + if d.is_dir() and d.name.startswith("date="): + dates.append(d.name[5:]) + if len(dates) < 1: + return None + dates.sort() + return [dates[0], dates[-1]] + + +@router.get("") +def list_configs(request: Request): + """列出所有扩展数据配置。""" + configs = _store(request).load_all() + data_dir = _data_dir(request) + items = [] + for c in configs: + d = c.to_dict() + d["latest_sync_date"] = _latest_sync_date(c, data_dir) + d["date_range"] = _date_range(c, data_dir) + items.append(d) + return {"items": items} + + +@router.post("") +def create_config(request: Request, body: CreateExtReq): + """创建扩展数据配置。""" + store = _store(request) + if store.get(body.id): + raise HTTPException(400, f"配置 '{body.id}' 已存在") + config = ExtConfig( + id=body.id, + label=body.label, + mode=body.mode, + fields=[ExtField(f.name, f.dtype, f.label) for f in body.fields], + description=body.description, + symbol_map=body.symbol_map, + code_map=body.code_map, + ) + store.upsert(config) + return config.to_dict() + + +@router.put("/{config_id}") +def update_config(request: Request, config_id: str, body: UpdateExtReq): + """更新扩展数据配置。""" + store = _store(request) + config = store.get(config_id) + if not config: + raise HTTPException(404, f"配置 '{config_id}' 不存在") + if body.label is not None: + config.label = body.label + if body.fields is not None: + config.fields = [ExtField(f.name, f.dtype, f.label) for f in body.fields] + if body.description is not None: + config.description = body.description + if body.symbol_map is not None: + config.symbol_map = body.symbol_map + if body.code_map is not None: + config.code_map = body.code_map + store.upsert(config) + return config.to_dict() + + +@router.delete("/{config_id}") +def delete_config(request: Request, config_id: str): + """删除扩展数据配置。""" + store = _store(request) + if not store.delete(config_id): + raise HTTPException(404, f"配置 '{config_id}' 不存在") + return {"status": "deleted"} + + +@router.get("/{config_id}/rows") +def list_rows( + request: Request, + config_id: str, + snapshot_date: str | None = Query(None, alias="date"), + columns: str | None = Query(None, description="逗号分隔的字段列表"), + limit: int = Query(1000, ge=1, le=20000), +): + """读取扩展数据明细。 + + - snapshot: 返回当前快照。 + - timeseries: 默认返回最新日期分区,也可通过 date=YYYY-MM-DD 指定。 + """ + config = _store(request).get(config_id) + if not config: + raise HTTPException(404, f"配置 '{config_id}' 不存在") + + data_dir = _data_dir(request) + df, active_date = _read_ext_dataframe(config, data_dir, snapshot_date) + df = _with_instrument_name(df, data_dir) + requested = [c.strip() for c in (columns or "").split(",") if c.strip()] + if requested: + keep = [c for c in ["symbol", "code", "name", *requested] if c in df.columns] + if keep: + df = df.select(list(dict.fromkeys(keep))) + total = len(df) + if total > limit: + df = df.head(limit) + + rows = [] + for row in df.to_dicts(): + rows.append({k: _safe_json_value(v) for k, v in row.items()}) + + return { + "id": config.id, + "label": config.label, + "mode": config.mode, + "date": active_date, + "total": total, + "limit": limit, + "fields": [f.to_dict() for f in config.fields], + "rows": rows, + } + + +# --------------------------------------------------------------------------- +# 文件上传 +# --------------------------------------------------------------------------- + +@router.post("/{config_id}/upload") +async def upload_data( + request: Request, + config_id: str, + file: UploadFile = File(...), + snapshot_date: str | None = None, +): + """上传 CSV/Excel 文件写入扩展数据。""" + store = _store(request) + config = store.get(config_id) + if not config: + raise HTTPException(404, f"配置 '{config_id}' 不存在") + + # 校验文件后缀 + suffix = Path(file.filename or "").suffix.lower() + if suffix not in (".csv", ".xlsx", ".xls"): + raise HTTPException(400, "仅支持 CSV / Excel 文件") + + # 写到临时文件再解析 + tmp_dir = Path(tempfile.mkdtemp()) + tmp_path = tmp_dir / f"upload{suffix}" + try: + with tmp_path.open("wb") as f: + content = await file.read() + f.write(content) + + # 直接读取文件,不做列重命名 + if suffix == ".csv": + df = pl.read_csv(tmp_path, infer_schema_length=10000) + elif suffix in (".xlsx", ".xls"): + df = pl.read_excel(tmp_path) + else: + raise HTTPException(400, f"不支持的文件格式: {suffix}") + + # 清洗列名:去掉括号内的时间戳等信息 + df = _clean_col_names(df) + + # 按映射关系自动生成 symbol 和 code 列 + df = _apply_mapping(df, config, _data_dir(request)) + except ValueError as e: + raise HTTPException(400, str(e)) from e + finally: + shutil.rmtree(tmp_dir, ignore_errors=True) + + # 确保配置的字段列存在于上传数据中(symbol/code 由映射自动生成,不校验) + auto_fields = {"symbol", "code"} + config_cols = {f.name for f in config.fields} - auto_fields + missing = config_cols - set(df.columns) + if missing: + raise HTTPException(400, f"上传数据缺少字段: {', '.join(sorted(missing))}") + + # 只保留配置中定义的列(包括自动生成的 symbol/code),忽略文件中多余的字段 + all_config_cols = {f.name for f in config.fields} + keep = [c for c in df.columns if c in all_config_cols] + df = df.select(keep) + + # 解析快照日期 + snap = date.fromisoformat(snapshot_date) if snapshot_date else date.today() + + rows = write_ext_parquet(df, config, _data_dir(request), snapshot_date=snap) + + # 刷新 DuckDB 视图 + _refresh_views(request) + + return {"status": "ok", "rows": rows, "date": snap.isoformat()} + + +# --------------------------------------------------------------------------- +# JSON 接口写入 +# --------------------------------------------------------------------------- + +@router.post("/{config_id}/ingest") +def ingest_data(request: Request, config_id: str, body: IngestReq): + """通过 JSON 接口批量写入扩展数据。""" + store = _store(request) + config = store.get(config_id) + if not config: + raise HTTPException(404, f"配置 '{config_id}' 不存在") + + # 校验必填字段 + configured = {f.name for f in config.fields} + required = configured - {"symbol"} + for i, row in enumerate(body.rows): + if "symbol" not in row: + raise HTTPException(400, f"第 {i + 1} 行缺少 symbol 字段") + missing = required - set(row.keys()) + if missing: + raise HTTPException(400, f"第 {i + 1} 行缺少字段: {', '.join(sorted(missing))}") + + snap = date.fromisoformat(body.date) if body.date else date.today() + + rows_written = rows_to_parquet(body.rows, config, _data_dir(request), snapshot_date=snap) + + _refresh_views(request) + + return {"status": "ok", "rows": rows_written, "date": snap.isoformat()} + + +# --------------------------------------------------------------------------- +# 定时拉取 +# --------------------------------------------------------------------------- + +@router.put("/{config_id}/pull") +def configure_pull(request: Request, config_id: str, body: PullConfigReq): + """配置(或更新)定时拉取。""" + store = _store(request) + config = store.get(config_id) + if not config: + raise HTTPException(404, f"配置 '{config_id}' 不存在") + + # 保留历史状态字段 + old_pull = config.pull + config.pull = PullConfig( + url=body.url, + method=body.method, + headers=body.headers, + body=body.body, + response_path=body.response_path, + field_map=body.field_map, + schedule_minutes=body.schedule_minutes, + enabled=body.enabled, + last_run=old_pull.last_run if old_pull else None, + last_status=old_pull.last_status if old_pull else None, + last_message=old_pull.last_message if old_pull else None, + last_rows=old_pull.last_rows if old_pull else None, + ) + store.upsert(config) + + # 刷新调度器 + pull_scheduler.refresh(_data_dir(request)) + + return {"status": "ok", "pull": config.pull.to_dict()} + + +@router.post("/{config_id}/pull/test") +async def test_pull(request: Request, config_id: str): + """测试拉取:请求外部 API 并返回预览数据,不写入。""" + store = _store(request) + config = store.get(config_id) + if not config: + raise HTTPException(404, f"配置 '{config_id}' 不存在") + if not config.pull or not config.pull.url: + raise HTTPException(400, "拉取未配置或 URL 为空") + + # 临时构建一个带新配置的 config 用于测试 + from app.services.ext_pull import _extract_rows, _apply_field_map + import httpx + + pull = config.pull + try: + async with httpx.AsyncClient(timeout=30) as client: + headers = pull.headers or {} + kwargs: dict = {"headers": headers} + if pull.method.upper() == "POST" and pull.body: + kwargs["content"] = pull.body + if "content-type" not in {k.lower() for k in headers}: + kwargs["headers"]["Content-Type"] = "application/json" + resp = await client.request(pull.method.upper(), pull.url, **kwargs) + resp.raise_for_status() + data = resp.json() + + rows = _extract_rows(data, pull.response_path) + preview = _apply_field_map(rows[:5], pull.field_map) + return { + "status": "ok", + "total_rows": len(rows), + "preview": preview, + "has_symbol": bool(rows and "symbol" in rows[0]), + } + except Exception as e: + raise HTTPException(400, f"测试失败: {e}") from e + + +@router.post("/{config_id}/pull/run") +async def run_pull(request: Request, config_id: str): + """手动触发一次拉取并写入。""" + store = _store(request) + config = store.get(config_id) + if not config: + raise HTTPException(404, f"配置 '{config_id}' 不存在") + if not config.pull or not config.pull.url: + raise HTTPException(400, "拉取未配置或 URL 为空") + + try: + n, d = await fetch_and_ingest(config, _data_dir(request)) + _refresh_views(request) + return {"status": "ok", "rows": n, "date": d} + except Exception as e: + raise HTTPException(400, f"拉取失败: {e}") from e + + +# --------------------------------------------------------------------------- +# --------------------------------------------------------------------------- +# Symbol 格式修复 +# --------------------------------------------------------------------------- + +@router.post("/{config_id}/fix-symbol") +def fix_symbol(request: Request, config_id: str): + """扫描已有 Parquet 数据,将 symbol 列标准化为 代码.交易所 格式。""" + store = _store(request) + config = store.get(config_id) + if not config: + raise HTTPException(404, f"配置 '{config_id}' 不存在") + + fixed = fix_symbol_format(config, _data_dir(request)) + _refresh_views(request) + return {"status": "ok", "fixed_files": fixed} + + +# --------------------------------------------------------------------------- +# Schema 发现 +# --------------------------------------------------------------------------- + +_POLARS_TYPE_MAP = { + "Int64": "int", "Int32": "int", "Int16": "int", "Int8": "int", + "UInt64": "int", "UInt32": "int", "UInt16": "int", "UInt8": "int", + "Float64": "float", "Float32": "float", + "Boolean": "bool", + "Utf8": "string", "String": "string", + "Date": "string", "Datetime": "string", "Duration": "string", + "Categorical": "string", +} + + +@router.post("/detect-fields") +async def detect_fields( + request: Request, + file: UploadFile = File(...), +): + """上传 CSV/Excel 文件,自动检测列名和类型。 + + 返回 symbol_candidates(数据匹配 000001.SZ 格式的列)和 + code_candidates(数据匹配 6位纯数字的列)。 + """ + suffix = Path(file.filename or "").suffix.lower() + if suffix not in (".csv", ".xlsx", ".xls"): + raise HTTPException(400, "仅支持 CSV / Excel 文件") + + tmp_dir = Path(tempfile.mkdtemp()) + tmp_path = tmp_dir / f"upload{suffix}" + try: + with tmp_path.open("wb") as f: + content = await file.read() + f.write(content) + + # 直接读取,不要求 symbol 列 + if suffix == ".csv": + df = pl.read_csv(tmp_path, infer_schema_length=10000) + elif suffix in (".xlsx", ".xls"): + df = pl.read_excel(tmp_path) + else: + raise HTTPException(400, f"不支持的文件格式: {suffix}") + except HTTPException: + raise + except Exception as e: + raise HTTPException(400, str(e)) from e + finally: + shutil.rmtree(tmp_dir, ignore_errors=True) + + # 清洗列名:去掉括号内的时间戳等信息 + df = _clean_col_names(df) + + # 构建字段列表 + fields = [] + for col_name in df.columns: + pl_type = df[col_name].dtype + dtype = _POLARS_TYPE_MAP.get(str(pl_type.base_type()), "string") + fields.append({"name": col_name, "dtype": dtype, "label": col_name}) + + # --- 分别检测 symbol 候选 (000001.SZ) 和 code 候选 (6位纯数字) --- + import re + _CODE_PAT = re.compile(r"^\d{6}$") + _SYMBOL_PAT = re.compile(r"^\d{6}\.[A-Z]{2}$") + + symbol_candidates: list[str] = [] # 数据匹配 000001.SZ 格式 + code_candidates: list[str] = [] # 数据匹配 000001 格式 + + for col in df.columns: + col_data = df[col].cast(pl.Utf8).drop_nulls() + if len(col_data) == 0: + continue + sample = col_data.head(200).to_list() + sym_hits = sum(1 for v in sample if _SYMBOL_PAT.match(str(v).strip())) + code_hits = sum(1 for v in sample if _CODE_PAT.match(str(v).strip())) + total = len(sample) + if total > 0: + if sym_hits / total > 0.5: + symbol_candidates.append(col) + elif code_hits / total > 0.5: + code_candidates.append(col) + + return { + "fields": fields, + "rows": len(df), + "symbol_candidates": symbol_candidates, + "code_candidates": code_candidates, + } + + +@router.get("/schema/{config_id}") +def discover_schema(request: Request, config_id: str): + """发现扩展数据的实际 Parquet schema(基于已有数据)。""" + config = _store(request).get(config_id) + if not config: + raise HTTPException(404, f"配置 '{config_id}' 不存在") + + data_dir = _data_dir(request) + glob = _parquet_glob(config, data_dir) + + try: + import duckdb + rows = duckdb.query( + f"SELECT column_name, data_type FROM (DESCRIBE SELECT * FROM read_parquet('{glob}', union_by_name=true))" + ).fetchall() + return {"columns": [{"name": r[0], "type": r[1]} for r in rows]} + except Exception: + # 无数据时返回配置中定义的字段 + return {"columns": [f.to_dict() for f in config.fields]} + + +@router.get("/schema-all") +def discover_all_schemas(request: Request): + """发现所有扩展表的 schema(用于前端动态列选择)。""" + configs = _store(request).load_all() + result = [] + for config in configs: + data_dir = _data_dir(request) + glob = _parquet_glob(config, data_dir) + + try: + import duckdb + cols = duckdb.query( + f"SELECT column_name, data_type FROM (DESCRIBE SELECT * FROM read_parquet('{glob}', union_by_name=true))" + ).fetchall() + field_labels = {f.name: f.label for f in config.fields} + columns = [{"name": r[0], "type": r[1], "label": field_labels.get(r[0], r[0])} for r in cols] + except Exception: + columns = [f.to_dict() for f in config.fields] + + result.append({ + "id": config.id, + "label": config.label, + "mode": config.mode, + "columns": columns, + }) + return {"items": result} + + +# --------------------------------------------------------------------------- +# 视图刷新 +# --------------------------------------------------------------------------- + +def _refresh_views(request: Request) -> None: + """重新注册 DuckDB 视图以包含新的扩展数据。""" + repo = request.app.state.repo + db = repo.store.db + d = repo.store.data_dir.as_posix() + + # 注册旧路径视图(兼容) + for name, subdir in [("instruments_ext", "instruments_ext"), ("kline_ext", "kline_ext")]: + old_glob = f"{d}/{subdir}/**/*.parquet" + old_dir = Path(d) / subdir + if old_dir.exists(): + sql = ( + f"CREATE OR REPLACE VIEW {name} AS " + f"SELECT * FROM read_parquet('{old_glob}', union_by_name=true)" + ) + try: + db.execute(sql) + except Exception: + pass + + # 注册新路径视图:每个扩展表一个视图 ext_{config_id} + ext_base = Path(d) / "ext_data" + if ext_base.exists(): + for cfg_dir in ext_base.iterdir(): + if not cfg_dir.is_dir(): + continue + cp = cfg_dir / "config.json" + if not cp.exists(): + continue + try: + raw = json.loads(cp.read_text(encoding="utf-8")) + cfg_id = raw["id"] + # 检查是否有数据文件(snapshot: part.parquet, timeseries: timeseries/ 目录) + has_data = (cfg_dir / "part.parquet").exists() or (cfg_dir / "timeseries").exists() + if has_data: + view_name = f"ext_{cfg_id}" + # snapshot: part.parquet 在 cfg_dir/ 根下; timeseries: 在 timeseries/ 子目录 + mode = raw.get("mode", "snapshot") + if mode == "snapshot": + glob_pattern = f"{cfg_dir.as_posix()}/*.parquet" + else: + glob_pattern = f"{cfg_dir.as_posix()}/timeseries/**/*.parquet" + sql = ( + f"CREATE OR REPLACE VIEW {view_name} AS " + f"SELECT * FROM read_parquet('{glob_pattern}', union_by_name=true)" + ) + db.execute(sql) + except Exception: + pass diff --git a/backend/app/api/financials.py b/backend/app/api/financials.py new file mode 100644 index 0000000..f642b6c --- /dev/null +++ b/backend/app/api/financials.py @@ -0,0 +1,120 @@ +"""财务数据 API — 独立路由, Cap.FINANCIAL 门控。""" +from __future__ import annotations + +import logging + +import polars as pl +from fastapi import APIRouter, HTTPException, Request + +from app.services.financial_sync import get_financial_df +from app.tickflow.capabilities import Cap + +logger = logging.getLogger(__name__) + +router = APIRouter(prefix="/api/financials", tags=["financials"]) + + +@router.get("/status") +def financial_status(request: Request): + """返回各财务表的同步状态。无需 FINANCIAL 权限(前端根据 available 决定是否展示)。""" + capset = request.app.state.capabilities + if not capset.has(Cap.FINANCIAL): + return {"available": False, "tables": {}} + + data_dir = request.app.state.repo.store.data_dir + tables = {} + + for table in ("metrics", "income", "balance_sheet", "cash_flow"): + path = data_dir / "financials" / table / "part.parquet" + if path.exists(): + try: + df = pl.read_parquet(path, columns=["symbol"]) + tables[table] = { + "rows": len(df), + "symbols": df["symbol"].n_unique() if not df.is_empty() else 0, + } + except Exception: + tables[table] = {"rows": 0, "symbols": 0} + else: + tables[table] = {"rows": 0, "symbols": 0} + + fs = getattr(request.app.state, "financial_scheduler", None) + last_sync = fs.last_sync if fs else {} + + return {"available": True, "tables": tables, "last_sync": last_sync} + + +@router.get("/metrics") +def get_metrics(request: Request, symbol: str | None = None): + """查询核心财务指标。""" + capset = request.app.state.capabilities + capset.require(Cap.FINANCIAL) + + df = get_financial_df(request.app.state.repo.store.data_dir, "metrics") + if df.is_empty(): + return {"data": []} + if symbol: + df = df.filter(pl.col("symbol") == symbol) + return {"data": df.to_dicts()} + + +@router.get("/income") +def get_income(request: Request, symbol: str | None = None): + """查询利润表。""" + capset = request.app.state.capabilities + capset.require(Cap.FINANCIAL) + + df = get_financial_df(request.app.state.repo.store.data_dir, "income") + if df.is_empty(): + return {"data": []} + if symbol: + df = df.filter(pl.col("symbol") == symbol) + return {"data": df.to_dicts()} + + +@router.get("/balance-sheet") +def get_balance_sheet(request: Request, symbol: str | None = None): + """查询资产负债表。""" + capset = request.app.state.capabilities + capset.require(Cap.FINANCIAL) + + df = get_financial_df(request.app.state.repo.store.data_dir, "balance_sheet") + if df.is_empty(): + return {"data": []} + if symbol: + df = df.filter(pl.col("symbol") == symbol) + return {"data": df.to_dicts()} + + +@router.get("/cash-flow") +def get_cash_flow(request: Request, symbol: str | None = None): + """查询现金流量表。""" + capset = request.app.state.capabilities + capset.require(Cap.FINANCIAL) + + df = get_financial_df(request.app.state.repo.store.data_dir, "cash_flow") + if df.is_empty(): + return {"data": []} + if symbol: + df = df.filter(pl.col("symbol") == symbol) + return {"data": df.to_dicts()} + + +@router.post("/sync/{table}") +def sync_table(request: Request, table: str): + """手动触发同步。table: metrics / income / balance_sheet / cash_flow / all""" + capset = request.app.state.capabilities + capset.require(Cap.FINANCIAL) + + valid_tables = {"metrics", "income", "balance_sheet", "cash_flow", "all"} + if table not in valid_tables: + raise HTTPException(400, f"invalid table: {table}, expected one of {valid_tables}") + + fs = getattr(request.app.state, "financial_scheduler", None) + if not fs: + return {"status": "error", "message": "FinancialScheduler not available"} + + target = None if table == "all" else table + result = fs.run_now(target) + + return {"status": "ok", "synced": result} diff --git a/backend/app/api/indices.py b/backend/app/api/indices.py new file mode 100644 index 0000000..e78c2a2 --- /dev/null +++ b/backend/app/api/indices.py @@ -0,0 +1,149 @@ +"""指数 API。""" +from __future__ import annotations + +import logging +from datetime import date, datetime, timedelta +from typing import Optional + +import polars as pl +from fastapi import APIRouter, HTTPException, Query, Request + +from app.indicators.pipeline import compute_enriched +from app.services import index_sync, kline_sync +from app.tickflow.capabilities import Cap + +logger = logging.getLogger(__name__) + +router = APIRouter(prefix="/api/index", tags=["index"]) + + +def _index_info(repo, symbol: str) -> dict: + df = repo.get_index_instruments() + if df.is_empty() or "symbol" not in df.columns: + return {} + hit = df.filter(pl.col("symbol") == symbol).head(1) + if hit.is_empty(): + return {} + return hit.to_dicts()[0] + + +@router.get("/list") +def list_indices(request: Request): + """返回已缓存的 CN_Index 指数列表。""" + repo = request.app.state.repo + df = repo.get_index_instruments() + if df.is_empty(): + return {"results": [], "count": 0} + cols = [c for c in ["symbol", "name", "code", "asset_type"] if c in df.columns] + rows = df.select(cols).sort("symbol").to_dicts() + return {"results": rows, "count": len(rows)} + + +@router.get("/search") +def search_indices( + request: Request, + q: str = Query("", min_length=0, max_length=50, description="搜索关键词"), + limit: int = Query(20, ge=1, le=100), +): + """模糊搜索指数。""" + repo = request.app.state.repo + df = repo.get_index_instruments() + if df.is_empty(): + return {"results": []} + if not q.strip(): + rows = df.head(limit).to_dicts() + return {"results": rows} + + keyword = q.strip().upper() + masks = [] + if "code" in df.columns: + masks.append(pl.col("code").cast(pl.Utf8).str.contains(keyword, literal=True)) + masks.append(pl.col("symbol").cast(pl.Utf8).str.to_uppercase().str.contains(keyword, literal=True)) + if "name" in df.columns: + masks.append(pl.col("name").cast(pl.Utf8).str.contains(q.strip(), literal=True)) + + mask = masks[0] + for m in masks[1:]: + mask = mask | m + rows = df.filter(mask).head(limit).to_dicts() + return {"results": rows} + + +@router.get("/daily") +def get_index_daily( + request: Request, + symbol: str = Query(..., description="指数代码, 如 000001.SH"), + days: int = Query(120, ge=10, le=2000), + start_date: Optional[str] = Query(None, description="起始日期 YYYY-MM-DD, 优先于 days"), + end_date: Optional[str] = Query(None, description="截止日期 YYYY-MM-DD, 默认今天"), +): + """读取指数日 K。指数数据使用独立 kline_index_* parquet。""" + repo = request.app.state.repo + end = date.fromisoformat(end_date) if end_date else date.today() + start = date.fromisoformat(start_date) if start_date else end - timedelta(days=days) + info = _index_info(repo, symbol) + + df = repo.get_index_daily(symbol, start, end) + if not df.is_empty(): + return {"symbol": symbol, "name": info.get("name"), "index_info": info, "rows": df.to_dicts(), "source": "index_enriched"} + + capset = request.app.state.capabilities + if not capset.has(Cap.KLINE_DAILY_BATCH): + return {"symbol": symbol, "name": info.get("name"), "index_info": info, "rows": [], "source": "none"} + + try: + raw = kline_sync.sync_daily_batch([symbol], count=days + 150) + except Exception as e: # noqa: BLE001 + raise HTTPException(status_code=502, detail=f"TickFlow fetch failed: {e}") from e + if raw.is_empty(): + return {"symbol": symbol, "name": info.get("name"), "index_info": info, "rows": [], "source": "none"} + + enriched = compute_enriched(raw, factors=None, instruments=None) + rows = enriched.filter((pl.col("date") >= start) & (pl.col("date") <= end)).to_dicts() + return {"symbol": symbol, "name": info.get("name"), "index_info": info, "rows": rows, "source": "live"} + + +@router.get("/minute") +def get_index_minute( + request: Request, + symbol: str = Query(..., description="指数代码, 如 000001.SH"), + trade_date: date | None = Query(None, alias="date", description="交易日期, 默认今天"), +): + """实时读取指数分钟 K。不写入股票分钟 parquet。""" + repo = request.app.state.repo + info = _index_info(repo, symbol) + day = trade_date or date.today() + df = kline_sync.fetch_minute_single(symbol, day) + return { + "symbol": symbol, + "name": info.get("name"), + "index_info": info, + "date": str(day), + "rows": df.to_dicts(), + "source": "live" if not df.is_empty() else "none", + } + + +@router.post("/sync_instruments") +def sync_index_instruments(request: Request): + """同步 CN_Index 指数标的列表。""" + repo = request.app.state.repo + count = index_sync.sync_index_instruments(repo) + return {"status": "ok", "count": count} + + +@router.post("/sync_daily") +def sync_index_daily( + request: Request, + days: int = Query(365, ge=30, le=5000), +): + """同步指数日K到独立 parquet。""" + repo = request.app.state.repo + capset = request.app.state.capabilities + if not capset.has(Cap.KLINE_DAILY_BATCH): + raise HTTPException(status_code=403, detail="需要 Pro+ 权限 (batch K-line)") + end = datetime.now() + start = end - timedelta(days=days) + count = index_sync.sync_index_instruments(repo) + rows = index_sync.sync_and_persist_index_daily(repo, capset, start_date=start, end_date=end) + return {"status": "ok", "index_count": count, "rows_written": rows} diff --git a/backend/app/api/intraday.py b/backend/app/api/intraday.py new file mode 100644 index 0000000..988d476 --- /dev/null +++ b/backend/app/api/intraday.py @@ -0,0 +1,183 @@ +"""行情状态 / SSE 推送 API。 + +盘中选股相关端点已迁移至策略页面,此处仅保留全局行情基础设施。 +SSE 推送两种事件 (使用标准 SSE event 字段): + - quotes_updated: 行情数据刷新,前端 invalidate 对应 query + - strategy_alert: 策略监控/告警触发,前端弹通知 +""" +from __future__ import annotations + +import asyncio +import json +import time + +from fastapi import APIRouter, Query, Request +from sse_starlette.sse import EventSourceResponse + +router = APIRouter(prefix="/api/intraday", tags=["quotes"]) + + +def _get_quote_service(request: Request): + """获取全局 QuoteService。""" + return getattr(request.app.state, "quote_service", None) + + +def _fallback_index_quotes_from_daily(request: Request, symbols: list[str] | None = None) -> list[dict]: + """实时指数缓存为空时,从本地指数日 K 取最近收盘价作为兜底。""" + repo = getattr(request.app.state, "repo", None) + if not repo: + return [] + + params: list[str] = [] + symbol_filter = "" + if symbols: + placeholders = ", ".join("?" for _ in symbols) + symbol_filter = f"WHERE symbol IN ({placeholders})" + params.extend(symbols) + + try: + rows = repo.execute_all( + f""" + WITH ranked AS ( + SELECT symbol, date, close, + row_number() OVER (PARTITION BY symbol ORDER BY date DESC) AS rn + FROM kline_index_daily + {symbol_filter} + ), latest AS ( + SELECT symbol, + max(CASE WHEN rn = 1 THEN date END) AS date, + max(CASE WHEN rn = 1 THEN close END) AS last_price, + max(CASE WHEN rn = 2 THEN close END) AS prev_close + FROM ranked + WHERE rn <= 2 + GROUP BY symbol + ) + SELECT latest.symbol, latest.date, latest.last_price, latest.prev_close + FROM latest + ORDER BY latest.symbol + """, + params, + ) + except Exception: # noqa: BLE001 + return [] + + out: list[dict] = [] + for symbol, dt, last_price, prev_close in rows: + change_amount = None + change_pct = None + if last_price is not None and prev_close not in (None, 0): + change_amount = float(last_price) - float(prev_close) + change_pct = change_amount / float(prev_close) * 100 + out.append({ + "symbol": symbol, + "name": None, + "date": str(dt) if dt else None, + "last_price": float(last_price) if last_price is not None else None, + "close": float(last_price) if last_price is not None else None, + "prev_close": float(prev_close) if prev_close is not None else None, + "change_amount": change_amount, + "change_pct": change_pct, + "source": "index_daily", + }) + return out + + +@router.get("/status") +def status(request: Request): + """行情状态 (来自全局 QuoteService)。""" + qs = _get_quote_service(request) + if qs: + return qs.status() + return {"enabled": False, "running": False, "symbol_count": 0, "index_symbol_count": 0, + "quote_age_ms": None, "is_trading_hours": False, "last_fetch_ms": None} + + +@router.get("/indices") +def index_quotes( + request: Request, + symbols: str | None = Query(None, description="逗号分隔的指数 symbol 列表"), +): + """返回实时指数行情缓存,不触发 TickFlow 请求。""" + symbol_list = [s.strip() for s in symbols.split(",") if s.strip()] if symbols else None + qs = _get_quote_service(request) + if not qs: + rows = _fallback_index_quotes_from_daily(request, symbol_list) + return {"rows": rows, "count": len(rows), "source": "index_daily"} + df = qs.get_index_quotes(symbol_list) + rows = df.to_dicts() if not df.is_empty() else [] + if not rows: + rows = _fallback_index_quotes_from_daily(request, symbol_list) + return {"rows": rows, "count": len(rows), "source": "index_daily"} + return {"rows": rows, "count": len(rows), "source": "realtime"} + + +@router.get("/stream") +async def quote_stream(request: Request): + """SSE 端点: 行情更新 + 告警推送。 + + 使用 sse-starlette EventSourceResponse: + - 标准 SSE event 字段,前端按 event name 监听 + - 内置断线检测,客户端断开立即终止 generator + - 内置 ping 心跳,保持连接活跃 + """ + qs = _get_quote_service(request) + + async def event_generator(): + while True: + # 同时等待行情更新和告警 + update_task = asyncio.ensure_future( + asyncio.to_thread(qs.wait_for_update, timeout=5.0) if qs else asyncio.sleep(5) + ) + alert_task = asyncio.ensure_future( + asyncio.to_thread(qs.wait_for_alert, timeout=5.0) if qs else asyncio.sleep(5) + ) + + done, pending = await asyncio.wait( + [update_task, alert_task], + timeout=30.0, + return_when=asyncio.FIRST_COMPLETED, + ) + for t in pending: + t.cancel() + + # 先推送告警 (如果有) + if qs: + alerts = qs.pop_alerts() + if alerts: + for chunk_start in range(0, len(alerts), 20): + chunk = alerts[chunk_start:chunk_start + 20] + yield { + "event": "strategy_alert", + "data": json.dumps({ + "ts": int(time.time() * 1000), + "alerts": chunk, + }, ensure_ascii=False), + } + + # 推送行情更新 + update_result = None + for t in done: + try: + update_result = t.result() + except Exception: # noqa: BLE001 + pass + + if update_result: + yield { + "event": "quotes_updated", + "data": json.dumps({ + "ts": int(time.time() * 1000), + "symbol_count": qs._symbol_count if qs else 0, + }), + } + + return EventSourceResponse(event_generator()) + + +@router.post("/refresh") +def refresh_quotes(request: Request): + """手动刷新一次行情数据。""" + qs = _get_quote_service(request) + if qs: + return qs.refresh() + return {"error": "QuoteService not available"} diff --git a/backend/app/api/kline.py b/backend/app/api/kline.py new file mode 100644 index 0000000..14d9d36 --- /dev/null +++ b/backend/app/api/kline.py @@ -0,0 +1,716 @@ +"""K 线 / 同步 API。""" +from __future__ import annotations + +import logging +from datetime import date, timedelta +from typing import Optional + +from fastapi import APIRouter, HTTPException, Query, Request + +from app.indicators.pipeline import compute_enriched_single +from app.services import kline_sync + +logger = logging.getLogger(__name__) + +router = APIRouter(prefix="/api/kline", tags=["kline"]) + + +@router.get("/instruments/search") +def search_instruments( + request: Request, + q: str = Query("", min_length=0, max_length=50, description="搜索关键词"), + limit: int = Query(20, ge=1, le=50), +): + """模糊搜索标的 (代码 / 名称)。从内存 instruments 缓存中查。""" + repo = request.app.state.repo + df = repo.get_instruments() + if df.is_empty() or not q.strip(): + return {"results": []} + + keyword = q.strip().upper() + import polars as pl + + # code/symbol 前缀优先,再 name 包含匹配 + prefix_mask = ( + pl.col("code").str.starts_with(keyword) + | pl.col("symbol").str.to_uppercase().str.starts_with(keyword) + ) + contains_mask = ( + pl.col("code").str.contains(keyword, literal=True) + | pl.col("symbol").str.to_uppercase().str.contains(keyword, literal=True) + | pl.col("name").str.contains(keyword, literal=True) + ) + + # 前缀匹配优先,剩余名额用包含匹配补充 + prefix_hits = df.filter(prefix_mask).head(limit) + if prefix_hits.height >= limit: + matched = prefix_hits + else: + remaining = limit - prefix_hits.height + # 排除已匹配的 symbol + prefix_symbols = set(prefix_hits["symbol"].to_list()) if not prefix_hits.is_empty() else set() + contain_hits = df.filter(contains_mask & ~pl.col("symbol").is_in(prefix_symbols)).head(remaining) + matched = pl.concat([prefix_hits, contain_hits]) if not prefix_hits.is_empty() else contain_hits + rows = matched.select(["symbol", "name", "code"]).to_dicts() + return {"results": rows} + + +def _get_stock_info(repo, symbol: str) -> dict: + """从 instruments 视图查标的名称 + 股本。""" + try: + row = repo.execute_one( + "SELECT name, total_shares, float_shares FROM instruments WHERE symbol = ? LIMIT 1", + [symbol], + ) + except Exception: # noqa: BLE001 + return {} + if not row: + return {} + return { + "name": row[0], + "total_shares": row[1], + "float_shares": row[2], + } + + +@router.get("/daily") +def get_daily( + request: Request, + symbol: str = Query(..., description="标的代码,如 000001.SZ"), + days: int = Query(120, ge=10, le=2000), + start_date: Optional[str] = Query(None, description="起始日期 YYYY-MM-DD, 优先于 days"), + end_date: Optional[str] = Query(None, description="截止日期 YYYY-MM-DD, 默认今天"), +): + """读取本地 enriched 表中某只股票的日 K。 + + - 若 QuoteService 有实时行情, 追加/覆盖今日实时蜡烛 + - Free 用户: 若 enriched 表里没有该股票, 实时拉取 + 本地算 enriched 返回 + """ + import polars as pl + + repo = request.app.state.repo + end = date.fromisoformat(end_date) if end_date else date.today() + if start_date: + start = date.fromisoformat(start_date) + else: + start = end - timedelta(days=days) + + stock_info = _get_stock_info(repo, symbol) + stock_name = stock_info.get("name") + + # 从 enriched 表读取 (已含前复权 OHLCV + 技术指标 + 信号) + df = repo.get_daily(symbol, start, end) + + if df.is_empty(): + try: + raw = kline_sync.sync_daily_batch([symbol], count=days + 30) + except Exception as e: + raise HTTPException(status_code=502, detail=f"TickFlow fetch failed: {e}") from e + if raw.is_empty(): + return {"symbol": symbol, "name": stock_name, "stock_info": stock_info, "rows": []} + enriched = compute_enriched_single(raw) + rows = enriched.tail(days).to_dicts() + # 即使 live 模式也尝试追加实时蜡烛 + rows = _maybe_inject_live_candle(request, symbol, rows) + return {"symbol": symbol, "name": stock_name, "stock_info": stock_info, "rows": rows, "source": "live"} + + rows = df.to_dicts() + + # 追加/覆盖今日实时蜡烛 + rows = _maybe_inject_live_candle(request, symbol, rows) + + return {"symbol": symbol, "name": stock_name, "stock_info": stock_info, "rows": rows, "source": "enriched"} + + +def _maybe_inject_live_candle(request: Request, symbol: str, rows: list[dict]) -> list[dict]: + """如果 QuoteService 有实时 enriched 数据, 用实时数据生成今日蜡烛并追加/覆盖。""" + qs = getattr(request.app.state, "quote_service", None) + if not qs: + return rows + + df_today, enriched_date = qs.get_enriched_today() + if df_today.is_empty(): + return rows + + # 非交易日(周末/假日)缓存的行情日期 != 今天,跳过注入避免产生重复蜡烛 + if not enriched_date or enriched_date != date.today(): + return rows + + # 查找该 symbol 的实时 enriched 行 + import polars as pl + try: + q = df_today.filter(pl.col("symbol") == symbol).to_dicts() + if not q: + return rows + q = q[0] + except Exception: # noqa: BLE001 + return rows + + close_price = q.get("close") + if not close_price or close_price <= 0: + return rows + + today_str = str(enriched_date) + + # enriched 行已包含 OHLCV + 全套指标, 直接用它 + # 修复: API 在非交易时段可能返回 open/high/low=0, 用 close 填充避免异常蜡烛 + raw_open = q.get("open") + raw_high = q.get("high") + raw_low = q.get("low") + live_row: dict = { + "date": today_str, + "symbol": symbol, + "open": raw_open if raw_open and raw_open > 0 else close_price, + "high": raw_high if raw_high and raw_high > 0 else close_price, + "low": raw_low if raw_low and raw_low > 0 else close_price, + "close": close_price, + "volume": q.get("volume"), + "amount": q.get("amount"), + "change_pct": q.get("change_pct"), + "is_live": True, + } + # 补上 enriched 的技术指标字段 + for key in ("ma5", "ma10", "ma20", "ma30", "ma60", + "macd_dif", "macd_dea", "macd_hist", + "kdj_k", "kdj_d", "kdj_j", + "boll_upper", "boll_lower", + "rsi_6", "rsi_14", "rsi_24", + "atr_14", "vol_ratio_5d"): + if key in q and q[key] is not None: + live_row[key] = q[key] + + # 如果已有今天的 enriched 行, 覆盖; 否则追加 + found = False + for i, r in enumerate(rows): + if str(r.get("date")) == today_str: + r.update(live_row) + found = True + break + + if not found: + rows.append(live_row) + + return rows + + +class DailyBatchRequest: + """批量日K请求。""" + symbols: list[str] + days: int = 12 + + +@router.post("/daily-batch") +def get_daily_batch(request: Request, body: dict): + """批量获取多只股票最近 N 天日K (OHLCV)。 + + 用于自选列表迷你蜡烛图等场景,只返回基础列,不返回全部 enriched 指标。 + """ + symbols = body.get("symbols", []) + days = body.get("days", 12) + if not symbols: + return {"data": {}} + days = max(5, min(60, days)) + + repo = request.app.state.repo + import polars as pl + from datetime import date, timedelta + + end = date.today() + start = end - timedelta(days=days * 2) # 多取一些确保交易日够 + + cols = ["symbol", "date", "open", "high", "low", "close", "volume"] + df = repo.get_daily_batch(symbols, start, end, columns=cols) + + if df.is_empty(): + return {"data": {}} + + # 按 symbol 分组, 每只取最近 N 条 + result: dict[str, list[dict]] = {} + for sym in symbols: + sub = df.filter(pl.col("symbol") == sym).sort("date").tail(days) + if not sub.is_empty(): + result[sym] = sub.to_dicts() + + return {"data": result} + + +@router.get("/minute") +def get_minute( + request: Request, + symbol: str = Query(..., description="标的代码"), + trade_date: date | None = Query(None, alias="date", description="交易日期, 默认最新"), +): + """读取某只股票某天的分钟 K 线。 + + - 本地有完整数据(240条) → 直接返回 + - 本地无数据或不完整 → 从 TickFlow 实时拉取返回(不写入) + """ + repo = request.app.state.repo + stock_info = _get_stock_info(repo, symbol) + stock_name = stock_info.get("name") + + if trade_date is None: + trade_date = repo.latest_minute_date(symbol) + if trade_date is None: + # 本地无任何分钟K,尝试从 TickFlow 拉取当天 + trade_date = date.today() + df = kline_sync.fetch_minute_single(symbol, trade_date) + return { + "symbol": symbol, "name": stock_name, "stock_info": stock_info, + "date": str(trade_date), "rows": df.to_dicts(), "source": "live", + } + + df = repo.get_minute(symbol, trade_date) + + # 完整交易日应有 240 条分钟K;如果是今天(盘中),期望条数按已交易分钟估算 + expected = 240 + today = date.today() + if trade_date == today: + from datetime import datetime as _dt + now = _dt.now() + h, m = now.hour, now.minute + if h < 9 or (h == 9 and m < 30): + expected = 0 # 还没开盘 + elif h < 12 or (h == 12 and m == 0): + expected = (h - 9) * 60 + m - 30 # 9:30 起 + elif h < 13: + expected = 120 # 午休 + elif h < 15: + expected = 120 + (h - 13) * 60 + m + else: + expected = 240 + + is_complete = not df.is_empty() and len(df) >= expected * 0.9 # 允许 10% 容差 + + if is_complete: + return { + "symbol": symbol, "name": stock_name, "stock_info": stock_info, + "date": str(trade_date), "rows": df.to_dicts(), "source": "local", + } + + # 本地不完整或无数据 → 从 TickFlow 实时拉取 + live_df = kline_sync.fetch_minute_single(symbol, trade_date) + return { + "symbol": symbol, "name": stock_name, "stock_info": stock_info, + "date": str(trade_date), "rows": live_df.to_dicts(), + "source": "live" if not live_df.is_empty() else "none", + } + + +@router.post("/sync") +def sync_symbol( + request: Request, + symbol: str = Query(...), + days: int = Query(250, ge=10, le=2000), +): + """手动触发单股同步(Free 用户在 K 线页用)。""" + repo = request.app.state.repo + capset = request.app.state.capabilities + n = kline_sync.sync_and_persist_daily_batch([symbol], repo, capset, count=days) + return {"symbol": symbol, "rows_written": n} + + +@router.post("/sync_batch") +def sync_batch( + request: Request, + symbols: list[str], + days: int = Query(250, ge=10, le=2000), +): + repo = request.app.state.repo + capset = request.app.state.capabilities + n = kline_sync.sync_and_persist_daily_batch(symbols, repo, capset, count=days) + return {"symbols": symbols, "rows_written": n} + + +@router.post("/refresh_views") +def refresh_views(request: Request): + """刷新所有 DuckDB 视图(解决视图状态不一致问题)。""" + from app.jobs.daily_pipeline import _refresh_views + repo = request.app.state.repo + _refresh_views(repo) + return {"status": "ok"} + + +@router.post("/sync_minute") +async def sync_minute(request: Request): + """手动触发分钟 K 同步(全市场)。返回 pipeline job_id 可轮询进度。""" + import asyncio + + from app.services.pipeline_jobs import job_store + from app.api.data import invalidate_storage_cache + from app.services.preferences import get_minute_sync_days + from app.tickflow.capabilities import Cap + from app.tickflow.pools import get_pool + + repo = request.app.state.repo + capset = request.app.state.capabilities + + if not capset.has(Cap.KLINE_MINUTE_BATCH): + raise HTTPException(status_code=403, detail="需要 Pro+ 权限") + + job_id = job_store.create() + existing = job_store.get(job_id) + if existing and existing["status"] == "running": + return {"status": "reused", "job_id": job_id} + + async def task() -> None: + job_store.start(job_id) + loop = asyncio.get_event_loop() + + def progress(stage: str, pct: int, msg: str) -> None: + job_store.progress(job_id, stage, pct, msg) + + try: + progress("sync_minute", 5, "解析标的池…") + universe = sorted(set(get_pool("watchlist")) | set(get_pool("CN_Equity_A"))) + # 补充 instruments 全量标的,覆盖北交所、新股等 + inst_path = repo.store.data_dir / "instruments" / "instruments.parquet" + if inst_path.exists(): + try: + import polars as pl + inst = pl.read_parquet(inst_path, columns=["symbol"]) + universe = sorted(set(universe) | set(inst["symbol"].to_list())) + except Exception: # noqa: BLE001 + pass + progress("sync_minute", 10, f"标的池 {len(universe)} 只") + + days = get_minute_sync_days() + + def _run(): + return kline_sync.sync_and_persist_minute(universe, repo, capset, days=days) + + written = await loop.run_in_executor(_long_task_executor, _run) + + # 刷新视图 + from app.jobs.daily_pipeline import _refresh_single_view + _refresh_single_view(repo, "kline_minute") + + progress("done", 100, f"分钟 K 同步完成,{written} 行") + job_store.succeed(job_id, {"minute_rows": written, "universe_size": len(universe)}) + invalidate_storage_cache() + except Exception as e: # noqa: BLE001 + job_store.fail(job_id, str(e)) + invalidate_storage_cache() + + asyncio.create_task(task()) + return {"status": "started", "job_id": job_id} + + +@router.post("/extend_history") +async def extend_history(request: Request): + """向前扩展历史日K数据 — 独立于盘后管道。 + + body: { "value": int, "unit": "day"|"month"|"year" } + 返回 job_id,可轮询 /api/pipeline/jobs 查看进度。 + """ + import asyncio + import traceback as _tb + try: + body = await request.json() + value = body.get("value") + unit = body.get("unit", "month") + if not value or value <= 0: + raise HTTPException(status_code=400, detail="value 必须为正整数") + if unit not in ("day", "month", "year"): + raise HTTPException(status_code=400, detail="unit 只支持 day/month/year") + + repo = request.app.state.repo + capset = request.app.state.capabilities + + from app.tickflow.capabilities import Cap + if not capset.has(Cap.KLINE_DAILY_BATCH): + raise HTTPException(status_code=403, detail="需要 Pro+ 权限 (batch K-line)") + + from app.services.extend_history import run_extend_history + from app.services.pipeline_jobs import job_store + from app.api.data import invalidate_storage_cache + + job_id = job_store.create() + existing = job_store.get(job_id) + if existing and existing["status"] == "running": + return {"status": "reused", "job_id": job_id} + + async def task() -> None: + job_store.start(job_id) + loop = asyncio.get_event_loop() + + def progress(stage: str, pct: int, msg: str, + stage_pct: int | None = None, skip_log: bool = False) -> None: + job_store.progress(job_id, stage, pct, msg, + stage_pct=stage_pct, skip_log=skip_log) + + try: + result = await loop.run_in_executor( + _long_task_executor, + lambda: run_extend_history(repo, capset, value, unit, on_progress=progress), + ) + if "error" in result: + job_store.fail(job_id, result["error"]) + else: + job_store.succeed(job_id, result) + invalidate_storage_cache() + except Exception as e: + logger.exception("extend_history failed: job_id=%s", job_id) + job_store.fail(job_id, str(e)) + invalidate_storage_cache() + + asyncio.create_task(task()) + return {"status": "started", "job_id": job_id} + except HTTPException: + raise + except Exception as e: + logger.error("extend_history error: %s\n%s", e, _tb.format_exc()) + raise HTTPException(status_code=500, detail=str(e)) from e + + +@router.post("/rebuild_enriched") +async def rebuild_enriched(request: Request): + """全量重算 enriched 表 — 不获取任何数据,仅基于已有 kline_daily + adj_factor 重算复权+指标。 + + 返回 job_id,可轮询 /api/pipeline/jobs 查看进度。 + """ + import asyncio + try: + repo = request.app.state.repo + + from app.services.pipeline_jobs import job_store + from app.api.data import invalidate_storage_cache + + job_id = job_store.create() + existing = job_store.get(job_id) + if existing and existing["status"] == "running": + return {"status": "reused", "job_id": job_id} + + async def task() -> None: + job_store.start(job_id) + loop = asyncio.get_event_loop() + + def progress(stage: str, pct: int, msg: str, + stage_pct: int | None = None, skip_log: bool = False) -> None: + job_store.progress(job_id, stage, pct, msg, + stage_pct=stage_pct, skip_log=skip_log) + + try: + progress("rebuild_enriched", 10, "全量计算 enriched…") + from app.indicators.pipeline import run_pipeline + + def _batch_progress(cur: int, tot: int) -> None: + pct = 10 + int(85 * cur / tot) + progress("rebuild_enriched", pct, + f"计算指标 批次 {cur}/{tot}", + stage_pct=int(100 * cur / tot), skip_log=True) + + written = await loop.run_in_executor( + _long_task_executor, + lambda: run_pipeline(on_batch_done=_batch_progress), + ) + + enriched_dir = repo.store.data_dir / "kline_daily_enriched" + enriched_days = len(list(enriched_dir.glob("date=*"))) if enriched_dir.exists() else 0 + + # 刷新视图 + d = repo.store.data_dir.as_posix() + for view_name, glob in [ + ("kline_enriched", f"{d}/kline_daily_enriched/**/*.parquet"), + ]: + try: + repo.db.execute( + f"CREATE OR REPLACE VIEW {view_name} AS " + f"SELECT * FROM read_parquet('{glob}', union_by_name=true)" + ) + except Exception: + pass + + progress("rebuild_enriched", 100, f"完成,覆盖 {enriched_days} 天") + job_store.succeed(job_id, { + "enriched_days": enriched_days, + "enriched_rows": written, + }) + invalidate_storage_cache() + except Exception as e: + logger.exception("rebuild_enriched failed: job_id=%s", job_id) + job_store.fail(job_id, str(e)) + invalidate_storage_cache() + + asyncio.create_task(task()) + return {"status": "started", "job_id": job_id} + except Exception as e: + import traceback as _tb + logger.error("rebuild_enriched error: %s\n%s", e, _tb.format_exc()) + raise HTTPException(status_code=500, detail=str(e)) from e + + +# 长时间任务专用线程池(隔离于 FastAPI 默认线程池,防止阻塞请求处理) +import concurrent.futures as _cf +_long_task_executor = _cf.ThreadPoolExecutor(max_workers=2, thread_name_prefix="long-task") + + +@router.post("/extend_minute_history") +async def extend_minute_history(request: Request): + """向前扩展分钟K历史数据 — 仅拉数据,不做任何后续处理。 + + body: { "value": int, "unit": "day"|"month" } + 最大 15 天。返回 job_id,可轮询 /api/pipeline/jobs 查看进度。 + """ + import asyncio + import traceback as _tb + try: + body = await request.json() + value = body.get("value") + unit = body.get("unit", "day") + if not value or value <= 0: + raise HTTPException(status_code=400, detail="value 必须为正整数") + if unit not in ("day", "month"): + raise HTTPException(status_code=400, detail="unit 只支持 day/month") + + repo = request.app.state.repo + capset = request.app.state.capabilities + + from app.tickflow.capabilities import Cap + if not capset.has(Cap.KLINE_MINUTE_BATCH): + raise HTTPException(status_code=403, detail="需要 Pro+ 权限 (batch minute K-line)") + + # 计算天数,上限 15 + from datetime import timedelta + if unit == "month": + total_days = min(value * 30, 15) + else: + total_days = min(value, 15) + + if total_days <= 0: + raise HTTPException(status_code=400, detail="扩展范围无效") + + from app.services.pipeline_jobs import job_store + from app.api.data import invalidate_storage_cache + + job_id = job_store.create() + existing = job_store.get(job_id) + if existing and existing["status"] == "running": + return {"status": "reused", "job_id": job_id} + + async def task() -> None: + job_store.start(job_id) + loop = asyncio.get_event_loop() + + def progress(stage: str, pct: int, msg: str, + stage_pct: int | None = None, skip_log: bool = False) -> None: + job_store.progress(job_id, stage, pct, msg, + stage_pct=stage_pct, skip_log=skip_log) + + try: + # 获取当前最早日期 + earliest = repo.earliest_minute_date() + if not earliest: + # 本地无分钟K数据 → 以今天为基准往前获取 + from datetime import date as _date + latest = _date.today() + else: + latest = earliest + + new_start = latest - timedelta(days=total_days) + if new_start >= latest: + job_store.fail(job_id, "扩展范围无效") + invalidate_storage_cache() + return + + start_str = new_start.strftime("%Y-%m-%d") + end_str = latest.strftime("%Y-%m-%d") + + progress("extend_minute", 5, "解析标的池…") + universe = _resolve_minute_universe(capset, repo) + progress("extend_minute", 8, f"标的池: {len(universe)} 只") + + from app.tickflow.capabilities import Cap + + lim = capset.limits(Cap.KLINE_MINUTE_BATCH) + batch_size = lim.batch if lim and lim.batch else 100 + rpm = lim.rpm if lim else 30 + + def _run(): + """全部在 executor 线程里完成,避免阻塞事件循环。""" + from app.services.kline_sync import sync_minute_batch + from datetime import datetime as _dt + + def _chunk(cur: int, tot: int) -> None: + progress("extend_minute", 8 + int(85 * cur / tot), + f"分钟K 批次 {cur}/{tot}", stage_pct=int(100 * cur / tot), skip_log=True) + + df = sync_minute_batch( + universe, + start_time=_dt.combine(new_start, _dt.min.time()), + end_time=_dt.combine(latest, _dt.min.time()), + batch_size=batch_size, rpm=rpm, + on_chunk_done=_chunk, + ) + + written = 0 + day_count = 0 + if not df.is_empty(): + import polars as pl + df = df.with_columns(pl.col("datetime").dt.date().alias("_trade_date")) + for day_df in df.partition_by("_trade_date"): + trade_date = day_df["_trade_date"][0] + out = repo.store.data_dir / "kline_minute" / f"date={trade_date}" / "part.parquet" + out.parent.mkdir(parents=True, exist_ok=True) + if out.exists(): + existing_df = pl.read_parquet(out) + if "datetime" in existing_df.columns: + existing_df = existing_df.filter(pl.col("datetime").is_not_null()) + day_df = pl.concat([existing_df, day_df.drop("_trade_date")]).unique( + subset=["symbol", "datetime"], keep="last", + ) + else: + day_df = day_df.drop("_trade_date") + day_df = day_df.sort("symbol", "datetime") + day_df.write_parquet(out) + written += day_df.height + day_count += 1 + + # 刷新视图 + d = repo.store.data_dir.as_posix() + try: + repo.db.execute( + f"CREATE OR REPLACE VIEW kline_minute AS " + f"SELECT * FROM read_parquet('{d}/kline_minute/**/*.parquet', union_by_name=true)" + ) + except Exception: + pass + return written, day_count + + progress("extend_minute", 10, f"获取分钟K [{start_str} ~ {end_str}]…") + written, day_count = await loop.run_in_executor(_long_task_executor, _run) + + progress("extend_minute", 95, f"分钟K 完成,{day_count} 天") + job_store.succeed(job_id, { + "minute_days": day_count, + "universe_size": len(universe), + "earliest_before": (earliest or latest).isoformat(), + "earliest_after": new_start.isoformat(), + }) + invalidate_storage_cache() + except Exception as e: + logger.exception("extend_minute_history failed: job_id=%s", job_id) + job_store.fail(job_id, str(e)) + invalidate_storage_cache() + + asyncio.create_task(task()) + return {"status": "started", "job_id": job_id} + except HTTPException: + raise + except Exception as e: + logger.error("extend_minute_history error: %s\n%s", e, _tb.format_exc()) + raise HTTPException(status_code=500, detail=str(e)) from e + + +def _resolve_minute_universe(capset, repo) -> list[str]: + """分钟K标的池解析。""" + from app.tickflow.capabilities import Cap + if capset.has(Cap.KLINE_MINUTE_BATCH): + try: + from app.tickflow.pools import get_pool + all_a = get_pool("CN_Equity_A", refresh=True) + if all_a: + return sorted(all_a) + except Exception: + pass + return [] diff --git a/backend/app/api/overview.py b/backend/app/api/overview.py new file mode 100644 index 0000000..abb47b4 --- /dev/null +++ b/backend/app/api/overview.py @@ -0,0 +1,540 @@ +"""市场总览聚合 API。""" +from __future__ import annotations + +import math +import re +import time +from datetime import date +from typing import Any + +import polars as pl +from fastapi import APIRouter, Request + +from app.services.ext_data import ExtConfig, ExtConfigStore +from app.services.screener import ScreenerService + +router = APIRouter(prefix="/api/overview", tags=["overview"]) + +_CACHE_TTL = 5.0 +_cache: dict[str, Any] | None = None +_cache_key: str | None = None +_cache_ts: float = 0.0 + +CORE_INDEX_NAMES = { + "000001.SH": "上证指数", + "399001.SZ": "深证成指", + "399006.SZ": "创业板指", + "000680.SH": "科创综指", +} +CORE_INDEX_SYMBOLS = tuple(CORE_INDEX_NAMES.keys()) + +_DIMENSION_SEP = re.compile(r"[、,,;;|/\s]+") + + +def _dimension_field(config: ExtConfig, kind: str) -> str | None: + candidates = ["概念", "concept", "theme"] if kind == "concept" else ["行业", "industry", "sector"] + for candidate in candidates: + needle = candidate.lower() + for field in config.fields: + haystack = f"{field.name} {field.label}".lower() + if needle in haystack: + return field.name + return None + + +def _ext_files(data_dir, config: ExtConfig) -> list[str]: + base = data_dir / "ext_data" / config.id + if config.mode == "timeseries": + root = base / "timeseries" + return [str(p) for p in sorted(root.rglob("*.parquet")) if p.is_file()] + return [str(p) for p in sorted(base.glob("*.parquet")) if p.is_file()] + + +def _read_ext_rows(data_dir, config: ExtConfig, dimension_field: str) -> list[dict]: + files = _ext_files(data_dir, config) + if not files: + return [] + try: + df = pl.read_parquet(files, hive_partitioning=True) + except TypeError: + try: + df = pl.read_parquet(files) + except Exception: # noqa: BLE001 + return [] + except Exception: # noqa: BLE001 + return [] + if df.is_empty() or dimension_field not in df.columns: + return [] + + if config.mode == "timeseries" and "date" in df.columns: + latest = df.get_column("date").max() + if latest is not None: + df = df.filter(pl.col("date") == latest) + + symbol_cols = ["symbol", "code", "股票代码", "代码"] + for mapping in (config.symbol_map, config.code_map): + if isinstance(mapping, dict) and mapping.get("type") == "mapped" and mapping.get("col"): + symbol_cols.append(str(mapping["col"])) + cols = [] + for col in [dimension_field, *symbol_cols]: + if col in df.columns and col not in cols: + cols.append(col) + return df.select(cols).to_dicts() + + +def _dimension_values(raw: Any) -> list[str]: + if raw is None: + return [] + values = [v.strip() for v in _DIMENSION_SEP.split(str(raw).strip()) if v.strip()] + return values + + +def _symbol_keys(row: dict, config: ExtConfig) -> list[str]: + fields = ["symbol", "code", "股票代码", "代码"] + for mapping in (config.symbol_map, config.code_map): + if isinstance(mapping, dict) and mapping.get("type") == "mapped" and mapping.get("col"): + fields.append(str(mapping["col"])) + + keys: list[str] = [] + for field in fields: + raw = row.get(field) + if raw is None: + continue + text = str(raw).strip().upper() + if not text: + continue + keys.append(text) + if "." in text: + keys.append(text.split(".", 1)[0]) + return keys + + +def _dimension_rank(rows: list[dict], request: Request, kind: str, limit: int = 5, level: int | None = None) -> dict: + if not rows: + return {"leading": [], "lagging": []} + + quote_map: dict[str, dict] = {} + for row in rows: + symbol = str(row.get("symbol") or "").strip().upper() + if not symbol: + continue + quote_map[symbol] = row + quote_map[symbol.split(".", 1)[0]] = row + + store = ExtConfigStore(request.app.state.repo.store.data_dir) + groups: dict[str, dict[str, dict]] = {} + for config in store.load_all(): + field = _dimension_field(config, kind) + if not field: + continue + for ext_row in _read_ext_rows(request.app.state.repo.store.data_dir, config, field): + quote = None + for key in _symbol_keys(ext_row, config): + quote = quote_map.get(key) + if quote: + break + if not quote: + continue + symbol = str(quote.get("symbol") or "") + for value in _dimension_values(ext_row.get(field)): + # 行业按 "-" 拆分级: "银行-银行-股份制银行" → level=2 取"银行"(二级) + if level is not None and "-" in value: + parts = value.split("-") + value = parts[level - 1] if level <= len(parts) else parts[-1] + groups.setdefault(value, {})[symbol] = quote + + items = [] + for name, by_symbol in groups.items(): + stocks = list(by_symbol.values()) + changes = [_finite(s.get("change_pct")) for s in stocks] + changes = [v for v in changes if v is not None] + if not changes: + continue + leader = max(stocks, key=lambda s: _finite(s.get("change_pct")) or -999) + items.append({ + "name": name, + "count": len(stocks), + "avg_pct": sum(changes) / len(changes), + "up_count": sum(1 for v in changes if v > 0), + "down_count": sum(1 for v in changes if v < 0), + "amount": sum(_finite(s.get("amount")) or 0 for s in stocks), + "leader": { + "symbol": leader.get("symbol"), + "name": leader.get("name"), + "change_pct": _finite(leader.get("change_pct")), + }, + }) + + leading = sorted(items, key=lambda x: x["avg_pct"], reverse=True)[:limit] + lagging = sorted(items, key=lambda x: x["avg_pct"])[:limit] + return {"leading": leading, "lagging": lagging} + + +def _finite(v: Any) -> float | None: + if v is None: + return None + try: + f = float(v) + except (TypeError, ValueError): + return None + return f if math.isfinite(f) else None + + +def _json_safe(value: Any) -> Any: + if isinstance(value, dict): + return {k: _json_safe(v) for k, v in value.items()} + if isinstance(value, list): + return [_json_safe(v) for v in value] + if isinstance(value, float) and not math.isfinite(value): + return None + return value + + +def _board(symbol: str) -> str: + if symbol.endswith(".BJ"): + return "北交所" + if symbol.startswith(("300", "301")): + return "创业板" + if symbol.startswith(("688", "689")): + return "科创板" + if symbol.endswith(".SH"): + return "沪主板" + if symbol.endswith(".SZ"): + return "深主板" + return "其他" + + +def _score(value: float, low: float, high: float) -> int: + if high <= low: + return 50 + return max(0, min(100, round((value - low) / (high - low) * 100))) + + +def _quote_status(request: Request) -> dict: + qs = getattr(request.app.state, "quote_service", None) + if not qs: + return {"enabled": False, "running": False, "quote_age_ms": None, "is_trading_hours": False} + return qs.status() + + +def _index_quotes(request: Request, as_of: date | None = None) -> list[dict]: + qs = getattr(request.app.state, "quote_service", None) + rows: list[dict] = [] + if qs and as_of is None: + df = qs.get_index_quotes(list(CORE_INDEX_SYMBOLS)) + if not df.is_empty(): + rows = df.to_dicts() + + if not rows: + repo = getattr(request.app.state, "repo", None) + if repo: + placeholders = ", ".join("?" for _ in CORE_INDEX_SYMBOLS) + try: + db_rows = repo.execute_all( + f""" + WITH ranked AS ( + SELECT symbol, date, close, + row_number() OVER (PARTITION BY symbol ORDER BY date DESC) AS rn + FROM kline_index_daily + WHERE symbol IN ({placeholders}) + AND (? IS NULL OR date <= ?) + ), latest AS ( + SELECT symbol, + max(CASE WHEN rn = 1 THEN date END) AS date, + max(CASE WHEN rn = 1 THEN close END) AS last_price, + max(CASE WHEN rn = 2 THEN close END) AS prev_close + FROM ranked + WHERE rn <= 2 + GROUP BY symbol + ) + SELECT symbol, date, last_price, prev_close + FROM latest + """, + [*CORE_INDEX_SYMBOLS, as_of, as_of], + ) + except Exception: # noqa: BLE001 + db_rows = [] + for symbol, dt, last_price, prev_close in db_rows: + change_amount = None + change_pct = None + lp = _finite(last_price) + pc = _finite(prev_close) + if lp is not None and pc not in (None, 0): + change_amount = lp - pc + change_pct = change_amount / pc * 100 + rows.append({ + "symbol": symbol, + "name": CORE_INDEX_NAMES.get(symbol), + "date": str(dt) if dt else None, + "last_price": lp, + "close": lp, + "prev_close": pc, + "change_amount": change_amount, + "change_pct": change_pct, + }) + + by_symbol = {r.get("symbol"): r for r in rows} + out = [] + for symbol in CORE_INDEX_SYMBOLS: + r = by_symbol.get(symbol, {"symbol": symbol}) + out.append({ + "symbol": symbol, + "name": r.get("name") or CORE_INDEX_NAMES[symbol], + "last_price": _finite(r.get("last_price") if r.get("last_price") is not None else r.get("close")), + "change_pct": _finite(r.get("change_pct")), + "change_amount": _finite(r.get("change_amount")), + }) + return out + + +def _top_rows(rows: list[dict], key: str, descending: bool, limit: int = 8) -> list[dict]: + filtered = [r for r in rows if _finite(r.get(key)) is not None] + filtered.sort(key=lambda r: _finite(r.get(key)) or 0, reverse=descending) + return [ + { + "symbol": r.get("symbol"), + "name": r.get("name"), + "close": _finite(r.get("close")), + "change_pct": _finite(r.get("change_pct")), + "amount": _finite(r.get("amount")), + "turnover_rate": _finite(r.get("turnover_rate")), + "board": _board(str(r.get("symbol") or "")), + } + for r in filtered[:limit] + ] + + +def _pct_band_rows(values: list[float]) -> list[dict]: + bands = [ + ("<-5%", None, -0.05), + ("-5~-3%", -0.05, -0.03), + ("-3~-1%", -0.03, -0.01), + ("-1~0%", -0.01, 0), + ("0~1%", 0, 0.01), + ("1~3%", 0.01, 0.03), + ("3~5%", 0.03, 0.05), + (">5%", 0.05, None), + ] + total = len(values) or 1 + out = [] + for label, low, high in bands: + count = 0 + for v in values: + if low is None and v < high: + count += 1 + elif high is None and v >= low: + count += 1 + elif low is not None and high is not None and low <= v < high: + count += 1 + out.append({"label": label, "count": count, "pct": count / total * 100}) + return out + + +def _build_overview(request: Request, as_of: date | None = None) -> dict: + repo = request.app.state.repo + svc = ScreenerService(repo) + as_of = as_of or svc.latest_date() + status = _quote_status(request) + indices = _index_quotes(request, as_of) + + if not as_of: + return { + "as_of": None, + "quote_status": status, + "indices": indices, + "breadth": {"total": 0, "up": 0, "down": 0, "flat": 0, "up_pct": 0, "down_pct": 0}, + "amount": {"total": 0, "avg": 0}, + "boards": [], + "limit": {"limit_up": 0, "broken": 0, "failed": 0, "limit_down": 0, "max_boards": 0, "tiers": []}, + "distribution": [], + "trend": {"above_ma5": 0, "above_ma20": 0, "above_ma60": 0, "above_ma5_pct": 0, "above_ma20_pct": 0, "above_ma60_pct": 0, "new_high": 0, "new_low": 0}, + "activity": {"avg_turnover": 0, "high_turnover": 0, "high_vol_ratio": 0, "vol_ratio": 1}, + "radar": [], + "emotion": {"score": 50, "label": "暂无"}, + "top_gainers": [], + "top_losers": [], + "turnover_leaders": [], + "active_leaders": [], + "concept_rank": {"leading": [], "lagging": []}, + "industry_rank": {"leading": [], "lagging": []}, + } + + df = svc._load_enriched_for_date(as_of) + if df.is_empty(): + rows: list[dict] = [] + else: + cols = [ + "symbol", "name", "close", "change_pct", "amount", "turnover_rate", "volume", + "vol_ratio_5d", "consecutive_limit_ups", "signal_limit_up", "signal_broken_limit_up", "signal_limit_down", + "ma5", "ma20", "ma60", "high_60d", "low_60d", "signal_n_day_high", "signal_n_day_low", + ] + df = df.select([c for c in cols if c in df.columns]) + rows = df.to_dicts() + + # 过滤真停牌(volume=0 且 change_pct=0),保留有涨跌幅的浮点误差股以对齐同花顺口径 + if rows and "volume" in rows[0]: + rows = [r for r in rows + if (_finite(r.get("volume")) or 0) > 0 + or (_finite(r.get("change_pct")) or 0) != 0] + + total = len(rows) + up = sum(1 for r in rows if (_finite(r.get("change_pct")) or 0) > 0) + down = sum(1 for r in rows if (_finite(r.get("change_pct")) or 0) < 0) + flat = max(0, total - up - down) + up_pct = up / total * 100 if total else 0 + down_pct = down / total * 100 if total else 0 + + amounts = [_finite(r.get("amount")) or 0 for r in rows] + total_amount = sum(amounts) + avg_amount = total_amount / total if total else 0 + + pct_values = [_finite(r.get("change_pct")) for r in rows] + pct_values = [v for v in pct_values if v is not None] + avg_pct = sum(pct_values) / len(pct_values) if pct_values else 0 + median_pct = sorted(pct_values)[len(pct_values) // 2] if pct_values else 0 + strong_up = sum(1 for v in pct_values if v >= 0.03) + strong_down = sum(1 for v in pct_values if v <= -0.03) + + limit_up = sum(1 for r in rows if bool(r.get("signal_limit_up")) or (_finite(r.get("consecutive_limit_ups")) or 0) > 0) + broken = sum(1 for r in rows if bool(r.get("signal_broken_limit_up"))) + limit_down = sum(1 for r in rows if bool(r.get("signal_limit_down"))) + max_boards = max([int(_finite(r.get("consecutive_limit_ups")) or 0) for r in rows], default=0) + seal_rate = limit_up / (limit_up + broken) * 100 if (limit_up + broken) > 0 else 0 + + def above_ma_count(ma_key: str) -> int: + return sum(1 for r in rows if (_finite(r.get("close")) is not None and _finite(r.get(ma_key)) is not None and (_finite(r.get("close")) or 0) >= (_finite(r.get(ma_key)) or 0))) + + above_ma5 = above_ma_count("ma5") + above_ma20 = above_ma_count("ma20") + above_ma60 = above_ma_count("ma60") + new_high = sum(1 for r in rows if bool(r.get("signal_n_day_high")) or (_finite(r.get("close")) is not None and _finite(r.get("high_60d")) is not None and (_finite(r.get("close")) or 0) >= (_finite(r.get("high_60d")) or 0))) + new_low = sum(1 for r in rows if bool(r.get("signal_n_day_low")) or (_finite(r.get("close")) is not None and _finite(r.get("low_60d")) is not None and (_finite(r.get("close")) or 0) <= (_finite(r.get("low_60d")) or 0))) + + turnovers = [_finite(r.get("turnover_rate")) for r in rows] + turnovers = [v for v in turnovers if v is not None] + avg_turnover = sum(turnovers) / len(turnovers) if turnovers else 0 + high_turnover = sum(1 for v in turnovers if v >= 5) + + boards_map: dict[str, dict] = {} + for r in rows: + b = _board(str(r.get("symbol") or "")) + item = boards_map.setdefault(b, {"board": b, "count": 0, "up": 0, "down": 0, "amount": 0.0}) + item["count"] += 1 + change = _finite(r.get("change_pct")) or 0 + if change > 0: + item["up"] += 1 + elif change < 0: + item["down"] += 1 + item["amount"] += _finite(r.get("amount")) or 0 + boards = sorted(boards_map.values(), key=lambda x: x["amount"], reverse=True) + for b in boards: + count = b["count"] or 1 + b["up_pct"] = b["up"] / count * 100 + + tiers_map: dict[int, int] = {} + for r in rows: + n = int(_finite(r.get("consecutive_limit_ups")) or 0) + if n > 0: + tiers_map[n] = tiers_map.get(n, 0) + 1 + tiers = [{"boards": k, "count": v} for k, v in sorted(tiers_map.items(), key=lambda item: -item[0])] + + index_changes = [_finite(r.get("change_pct")) for r in indices] + index_changes = [v for v in index_changes if v is not None] + avg_index_pct = sum(index_changes) / len(index_changes) if index_changes else 0 + vol_ratios = [_finite(r.get("vol_ratio_5d")) for r in rows] + vol_ratios = [v for v in vol_ratios if v is not None] + avg_vol_ratio = sum(vol_ratios) / len(vol_ratios) if vol_ratios else 1 + high_vol_ratio = sum(1 for v in vol_ratios if v >= 1.5) + + concept_rank = _dimension_rank(rows, request, "concept") + industry_rank = _dimension_rank(rows, request, "industry", level=2) + + strong_diff_pct = (strong_up - strong_down) / total * 100 if total else 0 + high_vol_pct = high_vol_ratio / total * 100 if total else 0 + strong_down_pct = strong_down / total * 100 if total else 0 + tier2_count = sum(t["count"] for t in tiers if t["boards"] >= 2) + mainline_items = [*concept_rank["leading"][:3], *industry_rank["leading"][:3]] + mainline_avg = max([_finite(item.get("avg_pct")) or 0 for item in mainline_items], default=0) + mainline_cover_pct = max([(_finite(item.get("count")) or 0) / total * 100 for item in mainline_items], default=0) if total else 0 + mainline_score = round(_score(mainline_avg, -0.005, 0.03) * 0.65 + _score(mainline_cover_pct, 1, 12) * 0.35) if mainline_items else 50 + + radar = [ + {"key": "index", "label": "指数", "value": _score(avg_index_pct, -2.5, 2.5)}, + {"key": "profit", "label": "赚钱", "value": round(_score(up_pct, 20, 80) * 0.45 + _score(avg_pct, -0.02, 0.02) * 0.25 + _score(median_pct, -0.02, 0.02) * 0.20 + _score(strong_diff_pct, -8, 8) * 0.10)}, + {"key": "money", "label": "量能", "value": round(_score(avg_vol_ratio, 0.6, 1.8) * 0.70 + _score(high_vol_pct, 2, 12) * 0.30)}, + {"key": "speculation", "label": "投机", "value": round(_score(limit_up, 5, 90) * 0.25 + _score(seal_rate, 30, 85) * 0.35 + _score(max_boards, 1, 8) * 0.25 + _score(tier2_count, 0, 30) * 0.15)}, + {"key": "resilience", "label": "抗跌", "value": 100 - round(_score(down_pct, 20, 80) * 0.55 + _score(strong_down_pct, 1, 12) * 0.45)}, + {"key": "mainline", "label": "主线", "value": mainline_score}, + ] + emotion_score = round(sum(r["value"] for r in radar) / len(radar)) if radar else 50 + if emotion_score >= 70: + emotion_label = "强势" + elif emotion_score >= 55: + emotion_label = "偏暖" + elif emotion_score >= 45: + emotion_label = "震荡" + elif emotion_score >= 30: + emotion_label = "偏冷" + else: + emotion_label = "冰点" + + return _json_safe({ + "as_of": str(as_of), + "quote_status": status, + "indices": indices, + "breadth": { + "total": total, + "up": up, + "down": down, + "flat": flat, + "up_pct": up_pct, + "down_pct": down_pct, + "avg_pct": avg_pct, + "median_pct": median_pct, + "strong_up": strong_up, + "strong_down": strong_down, + }, + "amount": {"total": total_amount, "avg": avg_amount}, + "boards": boards, + "limit": {"limit_up": limit_up, "broken": broken, "failed": 0, "limit_down": limit_down, "max_boards": max_boards, "seal_rate": seal_rate, "tiers": tiers}, + "distribution": _pct_band_rows(pct_values), + "trend": { + "above_ma5": above_ma5, + "above_ma20": above_ma20, + "above_ma60": above_ma60, + "above_ma5_pct": above_ma5 / total * 100 if total else 0, + "above_ma20_pct": above_ma20 / total * 100 if total else 0, + "above_ma60_pct": above_ma60 / total * 100 if total else 0, + "new_high": new_high, + "new_low": new_low, + }, + "activity": { + "avg_turnover": avg_turnover, + "high_turnover": high_turnover, + "high_vol_ratio": high_vol_ratio, + "vol_ratio": avg_vol_ratio, + }, + "radar": radar, + "emotion": {"score": emotion_score, "label": emotion_label}, + "top_gainers": _top_rows(rows, "change_pct", True), + "top_losers": _top_rows(rows, "change_pct", False), + "turnover_leaders": _top_rows(rows, "amount", True), + "active_leaders": _top_rows(rows, "turnover_rate", True), + "concept_rank": concept_rank, + "industry_rank": industry_rank, + }) + + +@router.get("/market") +def market_overview(request: Request, as_of: date | None = None): + """总览页单次请求聚合数据,避免前端拉全市场明细后再计算。""" + global _cache, _cache_key, _cache_ts + now = time.time() + cache_key = as_of.isoformat() if as_of else "latest" + if _cache is not None and _cache_key == cache_key and (now - _cache_ts) < _CACHE_TTL: + return _cache + data = _build_overview(request, as_of) + _cache = data + _cache_key = cache_key + _cache_ts = now + return data diff --git a/backend/app/api/pipeline.py b/backend/app/api/pipeline.py new file mode 100644 index 0000000..11f522b --- /dev/null +++ b/backend/app/api/pipeline.py @@ -0,0 +1,107 @@ +"""盘后管道 API — 异步触发 + 进度跟踪。""" +from __future__ import annotations + +import asyncio +import concurrent.futures as _cf +import logging + +from fastapi import APIRouter, HTTPException, Request + +from app.jobs import daily_pipeline +from app.services.pipeline_jobs import job_store +from app.api.data import invalidate_storage_cache + +# 长时间任务专用线程池(隔离于 FastAPI 默认线程池,防止阻塞请求处理) +_long_task_executor = _cf.ThreadPoolExecutor(max_workers=2, thread_name_prefix="long-task") + +logger = logging.getLogger(__name__) + +router = APIRouter(prefix="/api/pipeline", tags=["pipeline"]) + + +@router.post("/run") +async def run_now(request: Request) -> dict: + """异步触发盘后管道,立即返回 job_id。客户端轮询 /jobs/{id} 拿进度。 + + 若已有任务在跑,**返回该任务 id 而不是开新任务**(防止并发拉数据撞限流)。 + 但如果该任务已运行超过 10 分钟 (可能因 reload 卡死), 强制标记为失败后重新创建。 + """ + repo = request.app.state.repo + capset = request.app.state.capabilities + + # 检测卡死的 running job (如 reload 后孤儿 task) + existing_id = job_store.active_id() + if existing_id: + existing = job_store.get(existing_id) + if existing and existing["status"] == "running": + from datetime import datetime, timezone + started = existing.get("started_at") + if started: + try: + start_dt = datetime.fromisoformat(started.replace("Z", "+00:00")) + elapsed = (datetime.now(timezone.utc) - start_dt).total_seconds() + if elapsed > 600: # 超过 10 分钟视为卡死 + logger.warning("强制取消卡死 job %s (已运行 %.0fs)", existing_id, elapsed) + job_store.fail(existing_id, "超时自动取消 (疑似 reload 后孤儿 task)") + except Exception: + pass + + job_id = job_store.create() + + # 如果是复用的 active job,直接返回(不重启) + existing = job_store.get(job_id) + if existing and existing["status"] == "running": + return {"job_id": job_id, "reused": True} + + # 在 executor 里跑同步任务(pipeline 内部都是阻塞 IO + CPU) + async def task() -> None: + job_store.start(job_id) + loop = asyncio.get_event_loop() + + def progress(stage: str, pct: int, msg: str, stage_pct: int | None = None, + skip_log: bool = False) -> None: + job_store.progress(job_id, stage, pct, msg, stage_pct=stage_pct, skip_log=skip_log) + + try: + result = await loop.run_in_executor( + _long_task_executor, + lambda: daily_pipeline.run_now(repo, capset, on_progress=progress), + ) + job_store.succeed(job_id, result) + invalidate_storage_cache() + repo.refresh_cache() # 刷新 Polars 缓存 + except Exception as e: # noqa: BLE001 + logger.exception("pipeline failed") + job_store.fail(job_id, str(e)) + invalidate_storage_cache() + + asyncio.create_task(task()) + return {"job_id": job_id, "reused": False} + + +@router.get("/jobs/{job_id}") +def get_job(job_id: str) -> dict: + j = job_store.get(job_id) + if not j: + raise HTTPException(status_code=404, detail="job not found") + return j + + +@router.post("/jobs/{job_id}/cancel") +def cancel_job(job_id: str) -> dict: + """手动取消一个 running 的 job。""" + j = job_store.get(job_id) + if not j: + raise HTTPException(status_code=404, detail="job not found") + if j["status"] not in ("running", "pending"): + raise HTTPException(status_code=400, detail=f"job status is {j['status']}, cannot cancel") + job_store.fail(job_id, "用户手动取消") + return {"cancelled": job_id} + + +@router.get("/jobs") +def list_jobs(limit: int = 20) -> dict: + return { + "active_id": job_store.active_id(), + "jobs": job_store.list_recent(limit=limit), + } diff --git a/backend/app/api/routes.py b/backend/app/api/routes.py new file mode 100644 index 0000000..34d708e --- /dev/null +++ b/backend/app/api/routes.py @@ -0,0 +1,39 @@ +"""API 路由 — Phase 0 仅 /health 与 /api/capabilities。""" +from __future__ import annotations + +from fastapi import APIRouter + +from app import __version__ +from app.config import settings +from app.tickflow.policy import detect_capabilities, tier_label + +router = APIRouter() + + +@router.get("/health") +def health() -> dict: + return { + "status": "ok", + "version": __version__, + "mode": "free" if settings.use_free_mode else "api_key", + } + + +@router.get("/api/capabilities") +def capabilities() -> dict: + """前端用来决定哪些功能可用、哪些灰显。""" + capset = detect_capabilities() + return { + "label": tier_label(), + "capabilities": capset.to_dict(), + } + + +@router.post("/api/capabilities/redetect") +def redetect() -> dict: + """用户在设置页"重新检测"按钮。""" + capset = detect_capabilities(force=True) + return { + "label": tier_label(), + "capabilities": capset.to_dict(), + } diff --git a/backend/app/api/screener.py b/backend/app/api/screener.py new file mode 100644 index 0000000..9383f5a --- /dev/null +++ b/backend/app/api/screener.py @@ -0,0 +1,575 @@ +"""Screener API。""" +from __future__ import annotations + +import logging +import math +import re +import time +from dataclasses import asdict +from datetime import date, datetime +from typing import Any, Optional + +from fastapi import APIRouter, HTTPException, Query, Request +from pydantic import BaseModel + +from app.services.screener import PRESET_STRATEGIES, ScreenerService +from app.services import strategy_cache +from app.strategy import config as strategy_config + +logger = logging.getLogger(__name__) + +router = APIRouter(prefix="/api/screener", tags=["screener"]) + + +class CustomRequest(BaseModel): + conditions: list[str] + order_by: Optional[str] = None + limit: int = 30 + pool: Optional[list[str]] = None + as_of: Optional[date] = None + ext_columns: Optional[str] = None + + +class PresetRequest(BaseModel): + strategy_id: str + pool: Optional[list[str]] = None + as_of: Optional[date] = None + ext_columns: Optional[str] = None + + +def _safe(result_dict: dict) -> dict: + """sanitize for JSON(NaN / Inf → None).""" + rows = result_dict.get("rows", []) + for r in rows: + for k, v in list(r.items()): + if isinstance(v, float) and not math.isfinite(v): + r[k] = None + return result_dict + + +_EXT_IDENT_RE = re.compile(r"^[A-Za-z0-9_]+$") + + +def _safe_ext_value(value: Any) -> Any: + if isinstance(value, float) and not math.isfinite(value): + return None + if isinstance(value, (date, datetime)): + return value.isoformat() + return value + + +def _quote_ident(name: str) -> str: + return '"' + name.replace('"', '""') + '"' + + +def _load_ext_value_maps(repo, ext_columns: Optional[str]) -> dict[str, dict[str, Any]]: + """按请求加载扩展列,返回 {输出列名: {symbol: value}}。 + + 策略结果缓存是共享文件,不能被不同 ext_columns 组合污染;因此扩展列只在 + 返回前通过该投影映射追加到结果副本中。 + """ + ext_specs = _parse_ext_columns(ext_columns) if ext_columns else [] + if not ext_specs: + return {} + + import polars as pl + from app.api.ext_data import _read_ext_dataframe + from app.services.ext_data import ExtConfigStore + + db = repo.store.db + data_dir = repo.store.data_dir + ext_store = ExtConfigStore(data_dir) + configs = {c.id: c for c in ext_store.load_all()} + value_maps: dict[str, dict[str, Any]] = {} + + for config_id, field_name in ext_specs: + out_col = f"{config_id}__{field_name}" + cfg = configs.get(config_id) + try: + if cfg: + # 时序扩展表只取最新分区,避免历史分区把同一 symbol JOIN 放大。 + ext_df, _ = _read_ext_dataframe(cfg, data_dir) + else: + view_name = f"ext_{config_id}" + ext_df = pl.from_arrow(db.query( + f"SELECT symbol, {_quote_ident(field_name)} FROM {view_name}" + ).arrow()) + + if ext_df.is_empty() or "symbol" not in ext_df.columns or field_name not in ext_df.columns: + continue + + ext_df = ext_df.select(["symbol", field_name]).unique(subset=["symbol"], keep="last") + value_maps[out_col] = { + str(row["symbol"]): _safe_ext_value(row.get(field_name)) + for row in ext_df.to_dicts() + if row.get("symbol") + } + except Exception as e: # noqa: BLE001 + logger.debug("screener ext column join skipped for %s.%s: %s", config_id, field_name, e) + + return value_maps + + +def _row_with_ext(row: dict, ext_values: dict[str, dict[str, Any]], symbol: Optional[str] = None) -> dict: + next_row = dict(row) + sym = symbol or next_row.get("symbol") + for out_col, value_map in ext_values.items(): + next_row[out_col] = value_map.get(str(sym)) if sym else None + return next_row + + +def _rows_with_ext(rows: list[dict], ext_values: dict[str, dict[str, Any]]) -> list[dict]: + if not ext_values: + return rows + return [_row_with_ext(r, ext_values) for r in rows] + + +def _result_with_ext(result_dict: dict, ext_values: dict[str, dict[str, Any]]) -> dict: + if not ext_values: + return result_dict + return {**result_dict, "rows": _rows_with_ext(result_dict.get("rows", []), ext_values)} + + +def _results_with_ext(results: dict[str, dict], ext_values: dict[str, dict[str, Any]]) -> dict[str, dict]: + if not ext_values: + return results + return {sid: _result_with_ext(r, ext_values) for sid, r in results.items()} + + +def _cache_payload_with_ext(cached: dict, ext_values: dict[str, dict[str, Any]]) -> dict: + if not ext_values: + return cached + + payload = dict(cached) + payload["results"] = _results_with_ext(cached.get("results", {}), ext_values) + + ever_rows = cached.get("today_ever_rows") + if isinstance(ever_rows, dict): + enriched_ever: dict[str, dict[str, dict]] = {} + for sid, sym_map in ever_rows.items(): + if not isinstance(sym_map, dict): + continue + enriched_ever[sid] = { + sym: _row_with_ext(row, ext_values, symbol=sym) + for sym, row in sym_map.items() + if isinstance(row, dict) + } + payload["today_ever_rows"] = enriched_ever + + return payload + + +def _update_cache_strategy(data_dir, as_of: str, strategy_id: str, safe_data: dict) -> None: + """单跑后更新缓存中该策略的结果,保持缓存与最新计算一致。""" + from app.services import strategy_cache + cached = strategy_cache.read_cache(data_dir) + if cached and cached.get("as_of") == as_of: + results = cached.get("results", {}) + results[strategy_id] = { + "total": safe_data.get("total", 0), + "as_of": as_of, + "rows": safe_data.get("rows", []), + } + strategy_cache.write_cache(data_dir, as_of, results) + + +@router.get("/strategies") +def strategies(request: Request): + """策略清单(内置 + 自定义 + AI)。""" + data_dir = request.app.state.repo.store.data_dir + presets = [] + seen_ids: set[str] = set() + + # 内置策略 + for k, v in PRESET_STRATEGIES.items(): + overrides = strategy_config.load_override(data_dir, k) + name = (overrides.get("name") or v["name"]) if overrides else v["name"] + desc = (overrides.get("description") or v["description"]) if overrides else v["description"] + presets.append({"id": k, "name": name, "description": desc, "source": "builtin"}) + seen_ids.add(k) + + # 自定义/AI 策略(不在 PRESET_STRATEGIES 中的) + engine = getattr(request.app.state, "strategy_engine", None) + if engine: + for meta in engine.list_strategies(): + sid = meta["id"] + if sid not in seen_ids: + overrides = strategy_config.load_override(data_dir, sid) + name = (overrides.get("name") or meta["name"]) if overrides else meta["name"] + desc = (overrides.get("description") or meta.get("description", "")) if overrides else meta.get("description", "") + presets.append({"id": sid, "name": name, "description": desc, "source": meta.get("source", "custom")}) + seen_ids.add(sid) + + return {"presets": presets} + + +@router.post("/run") +def run_custom(req: CustomRequest, request: Request): + repo = request.app.state.repo + svc = ScreenerService(repo) + as_of = req.as_of or svc.latest_date() + if not as_of: + raise HTTPException(status_code=400, + detail="无可用数据日期 — enriched 表为空,请先运行盘后管道") + result = svc.run( + as_of=as_of, + conditions=req.conditions, + order_by=req.order_by, + limit=req.limit, + pool=req.pool, + ) + safe_data = _safe(asdict(result)) + ext_values = _load_ext_value_maps(repo, req.ext_columns) + return _result_with_ext(safe_data, ext_values) + + +@router.post("/run_preset") +def run_preset(req: PresetRequest, request: Request): + repo = request.app.state.repo + svc = ScreenerService(repo) + as_of = req.as_of or svc.latest_date() + if not as_of: + raise HTTPException(status_code=400, detail="无可用数据日期") + + # 加载用户保存的策略配置 + data_dir = request.app.state.repo.store.data_dir + ext_values = _load_ext_value_maps(repo, req.ext_columns) + overrides = strategy_config.load_override(data_dir, req.strategy_id) + bf = overrides.get("basic_filter") if overrides else None + dl = overrides.get("display_limit") if overrides else None + if dl is None and overrides and "display_limit" in overrides: + dl = 0 + + # 内置策略 + if req.strategy_id in PRESET_STRATEGIES: + try: + result = svc.run_preset(req.strategy_id, as_of=as_of, pool=req.pool, basic_filter=bf, display_limit=dl) + except ValueError as e: + raise HTTPException(status_code=404, detail=str(e)) from e + safe_data = _safe(asdict(result)) + _update_cache_strategy(data_dir, str(as_of), req.strategy_id, safe_data) + return _result_with_ext(safe_data, ext_values) + + # 自定义/AI 策略 — 通过 StrategyEngine 执行 + engine = getattr(request.app.state, "strategy_engine", None) + if not engine: + raise HTTPException(status_code=404, detail=f"策略引擎未初始化或策略 {req.strategy_id} 不存在") + + try: + result = engine.run(req.strategy_id, as_of, pool=req.pool, overrides=overrides or None) + except ValueError as e: + raise HTTPException(status_code=404, detail=str(e)) from e + + data = asdict(result) + + if dl is not None and dl > 0: + data["rows"] = data["rows"][:dl] + data["total"] = min(data["total"], dl) + + # 单跑后更新缓存中该策略的结果(保持缓存最新) + safe_data = _safe(data) + _update_cache_strategy(data_dir, str(as_of), req.strategy_id, safe_data) + + return _result_with_ext(safe_data, ext_values) + + +@router.get("/cached") +def get_cached( + request: Request, + ext_columns: Optional[str] = Query(None, description="逗号分隔: config_id.field_name"), +): + """读取策略结果缓存。返回 None 表示无缓存。""" + data_dir = request.app.state.repo.store.data_dir + cached = strategy_cache.read_cache(data_dir) + if cached is None: + return {"as_of": None, "results": {}, "updated_at": None} + ext_values = _load_ext_value_maps(request.app.state.repo, ext_columns) + return _cache_payload_with_ext(cached, ext_values) + + +@router.get("/market-snapshot") +def market_snapshot(request: Request): + """最新全市场轻量行情快照,供板块/概念聚合分析使用。""" + import polars as pl + + repo = request.app.state.repo + svc = ScreenerService(repo) + as_of = svc.latest_date() + if not as_of: + return {"as_of": None, "rows": []} + + df = svc._load_enriched_for_date(as_of) + if df.is_empty(): + return {"as_of": str(as_of), "rows": []} + + if "close" in df.columns and "total_shares" in df.columns and "market_cap" not in df.columns: + df = df.with_columns((pl.col("close") * pl.col("total_shares")).alias("market_cap")) + if "close" in df.columns and "float_shares" in df.columns and "float_market_cap" not in df.columns: + df = df.with_columns((pl.col("close") * pl.col("float_shares")).alias("float_market_cap")) + + cols = [ + "symbol", "name", "close", "change_pct", "amount", "volume", + "turnover_rate", "vol_ratio_5d", "total_shares", "float_shares", + "market_cap", "float_market_cap", "consecutive_limit_ups", + ] + df = df.select([c for c in cols if c in df.columns]) + rows = df.to_dicts() + for r in rows: + for k, v in list(r.items()): + if isinstance(v, float) and not math.isfinite(v): + r[k] = None + + return {"as_of": str(as_of), "rows": rows} + + +@router.post("/run_all") +def run_all(request: Request, body: Optional[dict] = None): + """批量运行指定策略,只返回每个策略的命中数。 + + 优化: 从 enriched 读取一次目标日期数据, 所有策略共享。 + body.strategy_ids: 只跑指定的策略 ID 列表, 为空则跑全部。 + """ + from datetime import date as date_type + + t_total = time.perf_counter() + + body = body or {} + repo = request.app.state.repo + svc = ScreenerService(repo) + + # 解析日期 + raw_date = body.get("as_of") + if raw_date: + as_of = date_type.fromisoformat(str(raw_date)) if isinstance(raw_date, str) else raw_date + else: + as_of = svc.latest_date() + if not as_of: + return {"as_of": None, "results": {}} + + # 一次读取目标日期的全部数据 + t0 = time.perf_counter() + precomputed = svc._load_enriched_for_date(as_of) + logger.info("run_all: _load_enriched_for_date took %.1fms", (time.perf_counter() - t0) * 1000) + + results: dict[str, dict] = {} + data_dir = request.app.state.repo.store.data_dir + + # 收集需要运行的策略 ID (如果指定了 strategy_ids 则只跑这些) + requested_ids = body.get("strategy_ids") + all_ids = list(PRESET_STRATEGIES.keys()) + engine = getattr(request.app.state, "strategy_engine", None) + if engine: + for meta in engine.list_strategies(): + sid = meta["id"] + if sid not in PRESET_STRATEGIES: + all_ids.append(sid) + + if requested_ids and isinstance(requested_ids, list): + id_set = set(requested_ids) + all_ids = [sid for sid in all_ids if sid in id_set] + + if not all_ids: + return {"as_of": str(as_of), "results": {}} + + # 批量预加载所有 override 配置 + t0 = time.perf_counter() + all_overrides = strategy_config.list_overrides(data_dir) + logger.info("run_all: list_overrides took %.1fms (%d overrides)", (time.perf_counter() - t0) * 1000, len(all_overrides)) + + # 历史策略: 只在需要时加载 (只加载 all_ids 中包含的 filter_history 策略) + t0 = time.perf_counter() + shared_history = None + id_set = set(all_ids) + if engine: + history_strats = [ + (sid, s) for sid, s in engine._strategies.items() + if s.filter_history_fn and sid in id_set + ] + if history_strats: + max_lb = min(max(s.lookback_days for _, s in history_strats), 30) + shared_history = svc._load_enriched_history(as_of, max(1, max_lb)) + else: + history_strats = [] + logger.info("run_all: _load_enriched_history took %.1fms (history_strats=%d)", (time.perf_counter() - t0) * 1000, len(history_strats)) + + for sid in all_ids: + try: + overrides = all_overrides.get(sid, {}) + bf = overrides.get("basic_filter") if overrides else None + dl = overrides.get("display_limit") if overrides else None + if dl is None and overrides and "display_limit" in overrides: + dl = 0 + + if sid in PRESET_STRATEGIES: + r = svc.run_preset(sid, as_of=as_of, precomputed=precomputed, basic_filter=bf, display_limit=dl) + else: + r = engine.run( + sid, as_of, overrides=overrides or None, + precomputed=precomputed, precomputed_history=shared_history, + ) + if dl is not None and dl > 0: + r.rows = r.rows[:dl] + r.total = min(r.total, dl) + + safe_rows = _safe(asdict(r)).get("rows", []) + results[sid] = {"total": r.total, "as_of": str(as_of), "rows": safe_rows} + except (ValueError, Exception): + continue + + elapsed = (time.perf_counter() - t_total) * 1000 + logger.info("run_all: total took %.1fms (%d strategies)", elapsed, len(all_ids)) + + # 写入策略缓存 (供页面秒加载) + if results: + try: + strategy_cache.write_cache(data_dir, str(as_of), results) + except Exception: # noqa: BLE001 + pass + + ext_values = _load_ext_value_maps(repo, body.get("ext_columns")) + return {"as_of": str(as_of), "results": _results_with_ext(results, ext_values)} + + +@router.get("/limit-ladder") +def limit_ladder( + request: Request, + as_of: Optional[date] = None, + ext_columns: Optional[str] = Query(None, description="逗号分隔: config_id.field_name"), +): + """连板梯队 — 按连板数分组, 含涨停/炸板/断板三种状态。 + 返回: tiers = [{ boards, count, stocks: [{symbol,name,change_pct,status,...}] }] + status: limit_up=涨停 | broken=炸板(摸板未封) | failed=断板(晋级失败) + ext_columns: 动态 JOIN 扩展数据, 如 "concept.concept,industry.industry" + """ + from datetime import timedelta + + import polars as pl + + repo = request.app.state.repo + svc = ScreenerService(repo) + as_of = as_of or svc.latest_date() + if not as_of: + raise HTTPException(status_code=400, detail="无可用数据日期") + + df = svc._load_enriched_for_date(as_of) + if df.is_empty(): + return {"as_of": str(as_of), "tiers": []} + + # 加载前一日数据获取 prev consecutive_limit_ups + prev_consec: pl.DataFrame = pl.DataFrame() + for delta in range(1, 10): + candidate = as_of - timedelta(days=delta) + df_prev = svc._load_enriched_for_date(candidate) + if not df_prev.is_empty() and "consecutive_limit_ups" in df_prev.columns: + prev_consec = df_prev.select( + "symbol", + pl.col("consecutive_limit_ups").alias("prev_consec"), + ) + break + + if not prev_consec.is_empty(): + df = df.join(prev_consec, on="symbol", how="left") + else: + df = df.with_columns(pl.lit(0).cast(pl.UInt32).alias("prev_consec")) + + # 表达式 + is_limit = pl.col("signal_limit_up").fill_null(False) if "signal_limit_up" in df.columns else pl.lit(False) + is_broken = pl.col("signal_broken_limit_up").fill_null(False) if "signal_broken_limit_up" in df.columns else pl.lit(False) + consec = pl.col("consecutive_limit_ups").fill_null(0) if "consecutive_limit_ups" in df.columns else pl.lit(0) + prev_c = pl.col("prev_consec").fill_null(0) + + # 计算 status + boards + is_failed = ~is_limit & ~is_broken & (prev_c > 0) + df = df.with_columns([ + pl.when(is_limit).then(pl.lit("limit_up")) + .when(is_broken).then(pl.lit("broken")) + .when(is_failed).then(pl.lit("failed")) + .otherwise(None).alias("status"), + pl.when(is_limit).then(consec) + .when(is_broken | is_failed).then(prev_c + 1) + .otherwise(0).cast(pl.UInt32).alias("boards"), + ]) + + df = df.filter(pl.col("status").is_not_null() & (pl.col("boards") > 0)) + + # 动态 JOIN 扩展数据 + ext_specs = _parse_ext_columns(ext_columns) if ext_columns else [] + ext_col_names: list[str] = [] + if ext_specs: + db = repo.store.db + data_dir = repo.store.data_dir + from app.services.ext_data import ExtConfigStore + + ext_store = ExtConfigStore(data_dir) + configs = {c.id: c for c in ext_store.load_all()} + + for config_id, field_name in ext_specs: + view_name = f"ext_{config_id}" + ext_col_name = f"{config_id}__{field_name}" + try: + ext_df = pl.from_arrow(db.query( + f"SELECT symbol, \"{field_name}\" FROM {view_name}" + ).arrow()) + if not ext_df.is_empty() and "symbol" in ext_df.columns: + ext_df = ext_df.rename({field_name: ext_col_name}) + df = df.join(ext_df.select(["symbol", ext_col_name]), on="symbol", how="left") + ext_col_names.append(ext_col_name) + except Exception: + cfg = configs.get(config_id) + if cfg: + try: + from app.api.ext_data import _parquet_glob + glob = _parquet_glob(cfg, data_dir) + ext_df = pl.read_parquet(glob) + if not ext_df.is_empty() and "symbol" in ext_df.columns and field_name in ext_df.columns: + ext_df = ext_df.select(["symbol", field_name]).rename({field_name: ext_col_name}) + df = df.join(ext_df, on="symbol", how="left") + ext_col_names.append(ext_col_name) + except Exception: + pass + + # 选择输出列 + cols = ["symbol", "name", "change_pct", "boards", "status"] + ext_col_names + df = df.select([c for c in cols if c in df.columns]) + # 排序: boards 降序, status 按涨停→炸板→断板 + status_order = pl.when(pl.col("status") == "limit_up").then(0) + status_order = status_order.when(pl.col("status") == "broken").then(1) + status_order = status_order.otherwise(2).alias("_status_order") + df = df.with_columns(status_order).sort(["boards", "_status_order"], descending=[True, False]).drop("_status_order") + + rows = df.to_dicts() + for r in rows: + for k, v in list(r.items()): + if isinstance(v, float) and not math.isfinite(v): + r[k] = None + + # 按 boards 分组 + tiers: dict[int, list] = {} + for r in rows: + n = int(r.get("boards") or 0) + tiers.setdefault(n, []).append(r) + + tier_list = [ + {"boards": n, "count": len(stocks), "stocks": stocks} + for n, stocks in sorted(tiers.items(), key=lambda x: -x[0]) + ] + + return {"as_of": str(as_of), "tiers": tier_list} + + +def _parse_ext_columns(ext_columns: str) -> list[tuple[str, str]]: + """解析 'config_id1.field1,config_id2.field2' 为 [(config_id, field_name), ...]。""" + result = [] + for part in ext_columns.split(","): + part = part.strip() + if "." not in part: + continue + config_id, field_name = part.split(".", 1) + config_id = config_id.strip() + field_name = field_name.strip() + if not config_id or not field_name: + continue + if not _EXT_IDENT_RE.match(config_id) or "\x00" in field_name: + continue + result.append((config_id, field_name)) + return result diff --git a/backend/app/api/settings.py b/backend/app/api/settings.py new file mode 100644 index 0000000..d3a3386 --- /dev/null +++ b/backend/app/api/settings.py @@ -0,0 +1,667 @@ +"""设置 API — Key 配置 / 模式切换。 + +提供面向非开发者的 UI 配置入口,避免逼用户改 .env。 +""" +from __future__ import annotations + +import logging +import time + +from fastapi import APIRouter, Request +from pydantic import BaseModel + +from app import secrets_store +from app.tickflow import client as tf_client +from app.tickflow.policy import ( + detect_capabilities, + extras_caps, + missing_caps, + probe_log, + tier_label, +) + +logger = logging.getLogger(__name__) + +router = APIRouter(prefix="/api/settings", tags=["settings"]) + +# 默认端点 —— endpoints.json 列表第一项,UI"当前使用"始终对齐此项。 +# 注意:Free 模式 SDK 实际走 free-api(免费数据通道),但 UI 显示统一用默认节点。 +DEFAULT_PAID_ENDPOINT = "https://api.tickflow.org" + + +class TickflowKeyIn(BaseModel): + api_key: str + + +@router.get("") +def get_settings() -> dict: + """返回当前配置概况(Key 脱敏)。""" + from app.config import settings + + key = secrets_store.get_tickflow_key() + return { + "mode": tf_client.current_mode(), + "tickflow_api_key_masked": secrets_store.mask(key), + "has_tickflow_key": bool(key), + "tier_label": tier_label(), + "current_endpoint": tf_client.current_endpoint(), + "probe_log": probe_log(), + "missing_caps": missing_caps(), + "extras_caps": extras_caps(), + # AI 配置 + "ai_provider": secrets_store.get_ai_config("ai_provider", settings.ai_provider), + "ai_base_url": secrets_store.get_ai_config("ai_base_url", settings.ai_base_url), + "ai_api_key_masked": secrets_store.mask(secrets_store.get_ai_key()), + "has_ai_key": bool(secrets_store.get_ai_key()), + "ai_model": secrets_store.get_ai_config("ai_model", settings.ai_model), + "ai_daily_token_budget": int(secrets_store.get_ai_config("ai_daily_token_budget", str(settings.ai_daily_token_budget)) or settings.ai_daily_token_budget), + } + + +class SwitchEndpointIn(BaseModel): + url: str + + +@router.post("/switch_endpoint") +def switch_endpoint(req: SwitchEndpointIn, request: Request) -> dict: + """切换 TickFlow 端点并立即生效。 + + endpoints.json 里的端点都是 Starter+ 付费端点,Free 模式无 key + 无法使用,故 Free 模式下禁止切换。 + """ + # Free 模式没有付费端点权限,禁止切换 + if tf_client.current_mode() == "free": + return {"ok": False, "error": "Free 模式无法切换端点,请先配置 API Key"} + + url = req.url.strip().rstrip("/") + if not url.startswith("https://"): + return {"ok": False, "error": "仅支持 HTTPS 端点"} + + # 持久化到 secrets.json + secrets_store.save({"tickflow_base_url": url}) + # 重置客户端,下次调用自动用新端点 + tf_client.reset_clients() + + return { + "ok": True, + "current_endpoint": tf_client.current_endpoint(), + } + + +@router.post("/tickflow-key") +def save_tickflow_key(req: TickflowKeyIn, request: Request) -> dict: + """保存 TickFlow API Key 并立即重新探测能力。 + + 端点联动:Free → Starter+ 时,Free 模式残留的 free-api 端点不可用于 + 付费 Key,故自动切到默认付费端点(api.tickflow.org)。 + """ + key = req.api_key.strip() + if not key: + return {"ok": False, "error": "key empty"} + + # 判断是否 Free → Starter+ 转换(此前无 key) + was_free = tf_client.current_mode() == "free" + updates: dict = {"tickflow_api_key": key} + if was_free: + # 自动切到默认端点;之前的残留自定义 URL 不再适用 + updates["tickflow_base_url"] = DEFAULT_PAID_ENDPOINT + + secrets_store.save(updates) + tf_client.reset_clients() + + # 立即重新探测 + capset = detect_capabilities(force=True) + request.app.state.capabilities = capset + + return { + "ok": True, + "tickflow_api_key_masked": secrets_store.mask(key), + "mode": "api_key", + "tier_label": tier_label(), + "current_endpoint": tf_client.current_endpoint(), + "probe_log": probe_log(), + "capabilities_count": len(capset.all()), + } + + +@router.delete("/tickflow-key") +def clear_tickflow_key(request: Request) -> dict: + """清除 Key,退回 Free 模式。 + + 同时清除 tickflow_base_url(测速切换的自定义端点),使"当前使用" + 回到默认节点 api.tickflow.org;SDK 则自动用 free() 取免费数据。 + """ + secrets_store.clear("tickflow_api_key", "tickflow_base_url") + tf_client.reset_clients() + + capset = detect_capabilities(force=True) + request.app.state.capabilities = capset + + return { + "ok": True, + "mode": "free", + "tier_label": tier_label(), + "current_endpoint": tf_client.current_endpoint(), + "capabilities_count": len(capset.all()), + } + + +class AiSettingsIn(BaseModel): + provider: str = "openai_compat" + base_url: str = "" + api_key: str | None = None + model: str = "" + daily_token_budget: int = 500_000 + + +@router.post("/ai") +def save_ai_settings(req: AiSettingsIn) -> dict: + """保存 AI 配置(全部持久化到 secrets.json)""" + from app.config import settings + + updates: dict = {} + if req.provider: + updates["ai_provider"] = req.provider + settings.ai_provider = req.provider + if req.base_url: + updates["ai_base_url"] = req.base_url + settings.ai_base_url = req.base_url + if req.api_key is not None: + if req.api_key: + updates["ai_api_key"] = req.api_key + settings.ai_api_key = req.api_key + else: + secrets_store.clear("ai_api_key") + settings.ai_api_key = "" + if req.model: + updates["ai_model"] = req.model + settings.ai_model = req.model + updates["ai_daily_token_budget"] = req.daily_token_budget + settings.ai_daily_token_budget = req.daily_token_budget + + if updates: + secrets_store.save(updates) + + return {"ok": True} + + +# ===== 偏好设置 ===== + +class MinuteSyncPrefs(BaseModel): + minute_sync_enabled: bool + minute_sync_days: int = 5 + + +@router.get("/preferences") +def get_preferences() -> dict: + """返回用户偏好设置。""" + from app.services import preferences + return { + "realtime_quotes_enabled": preferences.get_realtime_quotes_enabled(), + "indices_nav_pinned": preferences.get_indices_nav_pinned(), + "minute_sync_enabled": preferences.get_minute_sync_enabled(), + "minute_sync_days": preferences.get_minute_sync_days(), + "pipeline_schedule": preferences.get_pipeline_schedule(), + "instruments_schedule": preferences.get_instruments_schedule(), + "enriched_batch_size": preferences.get_enriched_batch_size(), + "index_daily_batch_size": preferences.get_index_daily_batch_size(), + "watchlist_columns": preferences.get_watchlist_columns(), + "screener_result_columns": preferences.get_screener_result_columns(), + "sse_refresh_pages": preferences.get_sse_refresh_pages(), + "strategy_monitor_enabled": preferences.get_strategy_monitor_enabled(), + "strategy_monitor_ids": preferences.get_strategy_monitor_ids(), + "sidebar_index_symbols": preferences.get_sidebar_index_symbols(), + "nav_order": preferences.get_nav_order(), + "nav_hidden": preferences.get_nav_hidden(), + "screener_auto_run": preferences.get_screener_auto_run(), + } + + +@router.get("/preferences/watchlist-columns") +def get_watchlist_columns() -> dict: + """返回自选列表列配置。""" + from app.services import preferences + cols = preferences.get_watchlist_columns() + return {"columns": cols} + + +class NavOrderIn(BaseModel): + nav_order: list[str] + + +class NavHiddenIn(BaseModel): + nav_hidden: list[str] + + +@router.put("/preferences/nav-order") +def update_nav_order(req: NavOrderIn) -> dict: + """保存左侧菜单排序(内置页面 path + 扩展分析菜单 id 的有序列表)。""" + from app.services import preferences + saved = preferences.set_nav_order(req.nav_order) + return {"nav_order": saved} + + +@router.put("/preferences/nav-hidden") +def update_nav_hidden(req: NavHiddenIn) -> dict: + """保存左侧菜单隐藏项。""" + from app.services import preferences + saved = preferences.set_nav_hidden(req.nav_hidden) + return {"nav_hidden": saved} + + +@router.put("/preferences/watchlist-columns") +def update_watchlist_columns(req: dict) -> dict: + """保存自选列表列配置。""" + from app.services import preferences + columns = req.get("columns", []) + saved = preferences.set_watchlist_columns(columns) + return {"columns": saved} + + +@router.get("/preferences/screener-result-columns") +def get_screener_result_columns() -> dict: + """返回策略结果列表列配置。""" + from app.services import preferences + cols = preferences.get_screener_result_columns() + return {"columns": cols} + + +@router.put("/preferences/screener-result-columns") +def update_screener_result_columns(req: dict) -> dict: + """保存策略结果列表列配置。""" + from app.services import preferences + columns = req.get("columns", []) + saved = preferences.set_screener_result_columns(columns) + return {"columns": saved} + + +@router.put("/preferences/minute-sync") +def update_minute_sync(req: MinuteSyncPrefs) -> dict: + """保存分钟 K 同步偏好。""" + from app.services import preferences + days = max(1, min(30, req.minute_sync_days)) + preferences.save({ + "minute_sync_enabled": req.minute_sync_enabled, + "minute_sync_days": days, + }) + return { + "minute_sync_enabled": req.minute_sync_enabled, + "minute_sync_days": days, + } + + +class RealtimeQuotesPrefs(BaseModel): + realtime_quotes_enabled: bool + + +@router.put("/preferences/realtime-quotes") +def update_realtime_quotes(req: RealtimeQuotesPrefs, request: Request) -> dict: + """保存全局实时行情开关。""" + from app.services import preferences + preferences.save({"realtime_quotes_enabled": req.realtime_quotes_enabled}) + + # 动态启停行情服务 + qs = getattr(request.app.state, "quote_service", None) + if qs: + if req.realtime_quotes_enabled: + qs.enable() + else: + qs.disable() + + return {"realtime_quotes_enabled": req.realtime_quotes_enabled} + + +class IndicesNavPinnedPrefs(BaseModel): + indices_nav_pinned: bool + + +@router.put("/preferences/indices-nav-pinned") +def update_indices_nav_pinned(req: IndicesNavPinnedPrefs) -> dict: + """保存侧栏指数报价卡片固定显示开关。 + ON=常驻显示;OFF=跟随实时行情开关(仅实时开时显示)。""" + from app.services import preferences + preferences.save({"indices_nav_pinned": req.indices_nav_pinned}) + return {"indices_nav_pinned": req.indices_nav_pinned} + + +class RealtimeMonitorConfigIn(BaseModel): + sse_refresh_pages: dict[str, bool] | None = None + strategy_monitor_enabled: bool | None = None + strategy_monitor_ids: list[str] | None = None + sidebar_index_symbols: list[str] | None = None + screener_auto_run: bool | None = None + + +@router.put("/preferences/realtime-monitor") +def update_realtime_monitor_config(req: RealtimeMonitorConfigIn, request: Request) -> dict: + """更新实时监控配置。""" + from app.services import preferences + + cfg = req.model_dump(exclude_none=True) + result = preferences.set_realtime_monitor_config(cfg) + + # 如果策略监控开关变化,更新 StrategyMonitorService 的监控池 + if req.strategy_monitor_ids is not None or req.strategy_monitor_enabled is not None: + monitor = getattr(request.app.state, "strategy_monitor", None) + if monitor: + if preferences.get_strategy_monitor_enabled(): + # 从策略引擎加载监控配置 + engine = getattr(request.app.state, "strategy_engine", None) + ids = preferences.get_strategy_monitor_ids() + if engine and ids: + monitor.stop_all() + for sid in ids: + try: + s = engine.get(sid) + monitor.start(sid, { + "entry_signals": s.entry_signals, + "exit_signals": s.exit_signals, + "alerts": s.alerts, + }) + except ValueError: + pass + else: + monitor.stop_all() + + return result + + +class QuoteIntervalIn(BaseModel): + interval: float + + +@router.put("/preferences/quote-interval") +def update_quote_interval(req: QuoteIntervalIn, request: Request) -> dict: + """更新行情轮询间隔。按档位自动 clamp。""" + qs = getattr(request.app.state, "quote_service", None) + if not qs: + return {"interval": req.interval, "min_interval": qs.get_min_interval(), "max_interval": 60.0} + clamped = qs.set_interval(req.interval) + return { + "interval": clamped, + "min_interval": qs.get_min_interval(), + "max_interval": qs.MAX_INTERVAL, + } + + +@router.get("/preferences/quote-interval") +def get_quote_interval(request: Request) -> dict: + """获取当前行情轮询间隔和档位限制。""" + qs = getattr(request.app.state, "quote_service", None) + if not qs: + return {"interval": 10.0, "min_interval": 5.0, "max_interval": 60.0} + return { + "interval": qs._interval, + "min_interval": qs.get_min_interval(), + "max_interval": qs.MAX_INTERVAL, + } + + +class TestEndpointIn(BaseModel): + url: str + # 测试轮数;不传时取 endpoints.json 的 testRounds(默认 5) + rounds: int | None = None + + +# 官方端点发现清单 —— 前端浏览器无法直接跨域拉取 tickflow.org/endpoints.json +# (无 CORS 头),因此由后端代理。缓存 5 分钟,失败时回退到内置列表。 +ENDPOINTS_URL = "https://tickflow.org/endpoints.json" +ENDPOINTS_TTL = 300.0 # 秒 + +# 回退列表 —— 与官方 endpoints.json 的 endpoints[] 字段对齐。 +# 当远程拉取失败时使用,保证 UI 永远有内容可显示。 +_FALLBACK_ENDPOINTS: list[dict] = [ + { + "id": "default", + "url": "https://api.tickflow.org", + "label": "默认端点", + "region": "auto", + "description": "默认端点", + "premium": False, + }, + { + "id": "hk", + "url": "https://hk-api.tickflow.org", + "label": "香港端点", + "region": "ap-east-1", + "description": "备用端点,部分地区访问更稳定", + "premium": False, + }, + { + "id": "sg", + "url": "https://sg-api.tickflow.org", + "label": "新加坡端点", + "region": "ap-southeast-1", + "description": "备用端点,亚太地区访问更稳定", + "premium": False, + }, + { + "id": "us", + "url": "https://us-api.tickflow.org", + "label": "美国端点", + "region": "us-east-1", + "description": "备用端点,欧美地区访问更稳定", + "premium": False, + }, + { + "id": "cn", + "url": "https://139.196.55.234:50443", + "label": "中国大陆端点(Beta)", + "region": "cn-east-1", + "description": "备用端点,中国大陆地区访问更稳定,目前处于测试阶段,谨慎使用", + "premium": False, + }, + { + "id": "cn-premium", + "url": "https://106.15.238.72:50443", + "label": "中国大陆专线端点", + "region": "cn-east-1", + "description": "专线加速端点,需要专线加速权限(该权限包含在 Expert 及以上套餐中,也可通过自定义组合单独开通)", + "premium": True, + }, +] + +# 进程内缓存:{ "ts": float, "data": dict } +_endpoints_cache: dict = {"ts": 0.0, "data": None} + + +@router.get("/endpoints") +def list_endpoints() -> dict: + """代理拉取 tickflow.org/endpoints.json 并返回规范化端点列表。 + + 前端无法跨域直连该 URL(无 CORS 头),故由本接口代理。带 8s 超时、 + 5 分钟内存缓存,远程失败时回退到内置列表,保证 UI 始终有内容。 + 返回结构与原始 endpoints.json 一致(透传 schema/version 等元信息)。 + """ + import httpx + + now = time.monotonic() + cached = _endpoints_cache.get("data") + if cached is not None and (now - _endpoints_cache["ts"]) < ENDPOINTS_TTL: + return cached + + source = "remote" + data: dict | None = None + try: + resp = httpx.get(ENDPOINTS_URL, timeout=8.0, follow_redirects=True) + if resp.status_code == 200: + parsed = resp.json() + eps = parsed.get("endpoints") + # 校验:必须是列表且每项含必要字段,否则视为无效 + if isinstance(eps, list) and all( + isinstance(e, dict) and "url" in e for e in eps + ): + data = { + "version": parsed.get("version", 1), + "description": parsed.get( + "description", "TickFlow API 端点配置" + ), + "healthPath": parsed.get("healthPath", "/health"), + "testRounds": parsed.get("testRounds", 5), + "endpoints": eps, + } + except (httpx.HTTPError, ValueError): + logger.warning("拉取 endpoints.json 失败,使用内置回退列表", exc_info=True) + + if data is None: + source = "fallback" + data = { + "version": 1, + "description": "TickFlow API 端点配置", + "healthPath": "/health", + "testRounds": 5, + "endpoints": _FALLBACK_ENDPOINTS, + } + + # 标记数据来源,便于前端提示(回退时显示"内置列表")。 + data["source"] = source + _endpoints_cache["ts"] = now + _endpoints_cache["data"] = data + return data + + +async def _http_ping(url: str, timeout: float = 10.0) -> float | None: + """单次异步 GET 请求并返回延迟(ms),失败返回 None。 + + 对齐官方 latency_test.py:用 /health 轻量端点测真实网络延迟, + 不携带 API Key(/health 公开)。异步实现,保证多端点并行测速不阻塞。 + """ + import httpx + + t0 = time.perf_counter() + try: + async with httpx.AsyncClient(timeout=timeout, follow_redirects=True) as client: + resp = await client.get(url) + dt = (time.perf_counter() - t0) * 1000 + # 只把 <400 视为成功;4xx/5xx 也算"不可达" + if resp.status_code < 400: + return round(dt, 2) + return None + except (httpx.TimeoutException, httpx.ConnectError, httpx.HTTPError, OSError): + return None + + +@router.post("/test_endpoint") +async def test_endpoint(req: TestEndpointIn) -> dict: + """测试端点网络延迟:对 /health 多轮探测取中位数。 + + 参考 TickFlow 官方 latency_test.py: + - 路径用 /health(公开、轻量),反映真实网络延迟而非业务接口耗时 + - 多轮探测(默认 5 轮,取自 endpoints.json 的 testRounds),间隔 0.3s + - 返回 median/min/max/success,前端显示中位数 + - 异步实现,保证"全部测速"时多端点真正并行 + """ + import asyncio + import statistics + + base = req.url.rstrip("/") + rounds = max(1, min(10, req.rounds or _endpoints_cache.get("data", {}).get("testRounds", 5))) + health_url = base + "/health" + + latencies: list[float] = [] + for _ in range(rounds): + ms = await _http_ping(health_url) + if ms is not None: + latencies.append(ms) + # 官方脚本间隔 0.3s;末轮无需等待 + await asyncio.sleep(0.3) + + success = len(latencies) + if success == 0: + return { + "ok": False, + "error": "不可达", + "url": req.url, + "rounds": rounds, + "success": 0, + "median_ms": None, + "min_ms": None, + "max_ms": None, + } + + median = round(statistics.median(latencies), 2) + return { + "ok": True, + "url": req.url, + "rounds": rounds, + "success": success, + "median_ms": median, + "min_ms": round(min(latencies), 2), + "max_ms": round(max(latencies), 2), + # 兼容旧字段:取中位数作为代表延迟 + "latency_ms": median, + } + + +class PipelineScheduleIn(BaseModel): + hour: int + minute: int + + +@router.put("/preferences/pipeline-schedule") +def update_pipeline_schedule(req: PipelineScheduleIn, request: Request) -> dict: + """保存盘后管道调度时间并立即 reschedule。""" + from app.services import preferences + sched = preferences.set_pipeline_schedule(req.hour, req.minute) + + # 动态 reschedule + from apscheduler.triggers.cron import CronTrigger + scheduler = getattr(request.app.state, "scheduler", None) + if scheduler: + scheduler.reschedule_job( + "daily_pipeline", + trigger=CronTrigger( + day_of_week="mon-fri", + hour=sched["hour"], + minute=sched["minute"], + timezone="Asia/Shanghai", + ), + ) + logger.info("pipeline rescheduled to %02d:%02d mon-fri", sched["hour"], sched["minute"]) + + return sched + + +@router.put("/preferences/instruments-schedule") +def update_instruments_schedule(req: PipelineScheduleIn, request: Request) -> dict: + """保存盘前标的维表调度时间并立即 reschedule。""" + from app.services import preferences + sched = preferences.set_instruments_schedule(req.hour, req.minute) + + from apscheduler.triggers.cron import CronTrigger + scheduler = getattr(request.app.state, "scheduler", None) + if scheduler: + scheduler.reschedule_job( + "pre_market_instruments", + trigger=CronTrigger( + day_of_week="mon-fri", + hour=sched["hour"], + minute=sched["minute"], + timezone="Asia/Shanghai", + ), + ) + return sched + + +class EnrichedBatchSizeIn(BaseModel): + size: int + + +@router.put("/preferences/enriched-batch-size") +def update_enriched_batch_size(req: EnrichedBatchSizeIn) -> dict: + """保存 enriched 全量计算批次大小。""" + from app.services import preferences + size = preferences.set_enriched_batch_size(req.size) + return {"enriched_batch_size": size} + + +class IndexDailyBatchSizeIn(BaseModel): + size: int + + +@router.put("/preferences/index-daily-batch-size") +def update_index_daily_batch_size(req: IndexDailyBatchSizeIn) -> dict: + """保存指数日 K 同步批次大小。""" + from app.services import preferences + size = preferences.set_index_daily_batch_size(req.size) + return {"index_daily_batch_size": size} diff --git a/backend/app/api/signals.py b/backend/app/api/signals.py new file mode 100644 index 0000000..66e1772 --- /dev/null +++ b/backend/app/api/signals.py @@ -0,0 +1,100 @@ +"""自定义信号 API 路由 — HTTP 请求 → 调用 custom_signals 模块 → 返回响应。 + +只做胶水:校验 → 持久化 → 失效缓存。不含表达式编译逻辑。 +""" +from __future__ import annotations + +from pathlib import Path + +from fastapi import APIRouter, HTTPException, Request +from pydantic import BaseModel + +from app.strategy import custom_signals + +router = APIRouter(prefix="/api/custom-signals", tags=["custom-signals"]) + + +def _data_dir(request: Request) -> Path: + return request.app.state.repo.store.data_dir + + +def _invalidate() -> None: + """失效 pipeline 的自定义信号缓存,下次计算重新加载。""" + from app.indicators.pipeline import invalidate_custom_signals + invalidate_custom_signals() + + +class ConditionModel(BaseModel): + left: str # 字段名(须在白名单) + op: str # > >= < <= == != + right: str # "field:xxx" 或数字字符串 + + +class SignalModel(BaseModel): + id: str + name: str + kind: str # entry | exit | both + conditions: list[ConditionModel] + enabled: bool = True + + +# ── 字段选项 / 运算符 ─────────────────────────────────── + + +@router.get("/options") +def get_options(): + """返回可选字段与运算符,供前端下拉框使用。""" + # 字段带中文标签(取自 ENRICHED_COLUMNS,回退为字段名本身) + from app.indicators.pipeline import ENRICHED_COLUMNS + + fields = [ + {"key": f, "label": ENRICHED_COLUMNS.get(f, f)} + for f in sorted(custom_signals.ALLOWED_FIELDS) + ] + return { + "fields": fields, + "operators": [">", ">=", "<", "<=", "==", "!="], + "kinds": [ + {"key": "entry", "label": "买入"}, + {"key": "exit", "label": "卖出"}, + {"key": "both", "label": "买卖通用"}, + ], + } + + +# ── 列表 ─────────────────────────────────────────────── + + +@router.get("") +def list_signals(request: Request): + sigs = custom_signals.load_all(_data_dir(request)) + return {"signals": sigs} + + +# ── 新建 / 更新 ──────────────────────────────────────── + + +@router.post("") +def save_signal(req: SignalModel, request: Request): + sig = req.model_dump() + try: + custom_signals.validate(sig) + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) + custom_signals.save_one(_data_dir(request), sig) + _invalidate() + return {"ok": True, "signal": sig} + + +# ── 删除 ─────────────────────────────────────────────── + + +@router.delete("/{signal_id}") +def delete_signal(signal_id: str, request: Request): + if not custom_signals.ID_RE.match(signal_id): + raise HTTPException(status_code=400, detail="信号 id 非法") + deleted = custom_signals.delete_one(_data_dir(request), signal_id) + if not deleted: + raise HTTPException(status_code=404, detail="信号不存在") + _invalidate() + return {"ok": True} diff --git a/backend/app/api/strategy.py b/backend/app/api/strategy.py new file mode 100644 index 0000000..a462e5e --- /dev/null +++ b/backend/app/api/strategy.py @@ -0,0 +1,468 @@ +"""策略 API 路由 — HTTP 请求 → 调用策略模块 → 返回响应。 + +只做胶水,不含业务逻辑。 +""" +from __future__ import annotations + +import math +from dataclasses import asdict +from datetime import date +from pathlib import Path +from typing import Any + +from fastapi import APIRouter, HTTPException, Request +from pydantic import BaseModel + +from app.strategy import config as strategy_config +from app.strategy.engine import StrategyEngine, StrategyDef +from app.strategy.ai_generator import AIStrategyGenerator +from app.strategy.prompt_builder import build_step1, build_step2 +from app.strategy.monitor import StrategyMonitorService, StrategyAlert + +router = APIRouter(prefix="/api/strategies", tags=["strategies"]) + +# ── Helpers ────────────────────────────────────────────────────────── + + +def _get_engine(request: Request) -> StrategyEngine: + engine = getattr(request.app.state, "strategy_engine", None) + if not engine: + raise HTTPException(status_code=503, detail="策略引擎未初始化") + return engine + + +def _get_monitor(request: Request) -> StrategyMonitorService: + mon = getattr(request.app.state, "strategy_monitor", None) + if not mon: + raise HTTPException(status_code=503, detail="策略监控未初始化") + return mon + + +def _data_dir(request: Request) -> Path: + return request.app.state.repo.store.data_dir + + +def _safe(result_dict: dict) -> dict: + rows = result_dict.get("rows", []) + for r in rows: + for k, v in list(r.items()): + if isinstance(v, float) and not math.isfinite(v): + r[k] = None + return result_dict + + +def _strategy_detail(s: StrategyDef, overrides: dict | None = None) -> dict: + """策略详情(含用户覆盖)""" + bf = {**s.basic_filter} + scoring = dict(s.meta.get("scoring", {})) + params_defaults = {p["id"]: p["default"] for p in s.meta.get("params", [])} + + if overrides: + if overrides.get("basic_filter"): + bf.update(overrides["basic_filter"]) + if overrides.get("scoring"): + scoring.update(overrides["scoring"]) + # 用户保存的参数覆盖默认值: 合并进 params_defaults, 前端据此回显 + if overrides.get("params"): + params_defaults.update(overrides["params"]) + + # 名称/描述可被用户覆盖 + name = overrides.get("name", s.meta.get("name", "")) if overrides else s.meta.get("name", "") + description = overrides.get("description", s.meta.get("description", "")) if overrides else s.meta.get("description", "") + + return { + "id": s.meta["id"], + "name": name or s.meta.get("name", ""), + "description": description or s.meta.get("description", ""), + "tags": s.meta.get("tags", []), + "source": s.source, + "version": s.meta.get("version", "1.0.0"), + "basic_filter": bf, + "params": s.meta.get("params", []), + "params_defaults": params_defaults, + "scoring": scoring, + "entry_signals": s.entry_signals, + "exit_signals": s.exit_signals, + "stop_loss": overrides.get("stop_loss", s.stop_loss) if overrides else s.stop_loss, + "trailing_stop": getattr(s, "trailing_stop", None), + "trailing_take_profit_activate": getattr(s, "trailing_take_profit_activate", None), + "trailing_take_profit_drawdown": getattr(s, "trailing_take_profit_drawdown", None), + "max_hold_days": overrides.get("max_hold_days", s.max_hold_days) if overrides else s.max_hold_days, + "alerts": s.alerts, + "order_by": s.meta.get("order_by", "score"), + "descending": s.meta.get("descending", True), + "limit": s.meta.get("limit", 30), + "display_limit": overrides.get("display_limit") if overrides and "display_limit" in overrides else None, + } + + +# ── Request Models ─────────────────────────────────────────────────── + + +class RunRequest(BaseModel): + strategy_id: str + as_of: date | None = None + pool: list[str] | None = None + params: dict | None = None + + +class RunAllRequest(BaseModel): + as_of: date | None = None + + +class SaveConfigRequest(BaseModel): + strategy_id: str + overrides: dict + + +class AIGenerateRequest(BaseModel): + prompt: str + + +class AISaveRequest(BaseModel): + code: str + strategy_id: str + + +class MonitorStartRequest(BaseModel): + strategy_id: str + + +# ── 列表 / 详情 ───────────────────────────────────────────────────── + + +@router.get("") +def list_strategies(request: Request): + engine = _get_engine(request) + data_dir = _data_dir(request) + all_overrides = strategy_config.list_overrides(data_dir) + + result = [] + for meta in engine.list_strategies(): + sid = meta["id"] + s = engine.get(sid) + overrides = all_overrides.get(sid) + result.append(_strategy_detail(s, overrides)) + return {"strategies": result} + + +@router.get("/{strategy_id}") +def get_strategy(strategy_id: str, request: Request): + engine = _get_engine(request) + try: + s = engine.get(strategy_id) + except ValueError as e: + raise HTTPException(status_code=404, detail=str(e)) from e + overrides = strategy_config.load_override(_data_dir(request), strategy_id) + return _strategy_detail(s, overrides or None) + + +# ── 执行选股 ───────────────────────────────────────────────────────── + + +@router.post("/run") +def run_strategy(req: RunRequest, request: Request): + engine = _get_engine(request) + data_dir = _data_dir(request) + + # 读取用户覆盖配置 + overrides = strategy_config.load_override(data_dir, req.strategy_id) + params = req.params or {} + # 合并用户保存的策略参数 + if overrides.get("params"): + merged = dict(overrides["params"]) + merged.update(params) # 请求里的优先 + params = merged + + # 确定日期 + as_of = req.as_of + if not as_of: + from app.services.screener import ScreenerService + svc = ScreenerService(request.app.state.repo) + as_of = svc.latest_date() + if not as_of: + raise HTTPException(status_code=400, detail="无可用数据日期") + + try: + result = engine.run( + req.strategy_id, as_of, + pool=req.pool, + params=params, + overrides=overrides or None, + ) + except ValueError as e: + raise HTTPException(status_code=404, detail=str(e)) from e + + return _safe(asdict(result)) + + +@router.post("/run-all") +def run_all(req: RunAllRequest, request: Request): + engine = _get_engine(request) + data_dir = _data_dir(request) + + as_of = req.as_of + if not as_of: + from app.services.screener import ScreenerService + svc = ScreenerService(request.app.state.repo) + as_of = svc.latest_date() + if not as_of: + return {"as_of": None, "results": {}} + + all_overrides = strategy_config.list_overrides(data_dir) + results: dict[str, dict] = {} + for sid, result in engine.run_all(as_of, overrides_map=all_overrides).items(): + results[sid] = {"total": result.total, "as_of": str(as_of)} + + return {"as_of": str(as_of), "results": results} + + +# ── 配置持久化 ─────────────────────────────────────────────────────── + + +@router.post("/config") +def save_config(req: SaveConfigRequest, request: Request): + engine = _get_engine(request) + if not engine.has(req.strategy_id): + raise HTTPException(status_code=404, detail=f"策略 {req.strategy_id} 不存在") + + # 剥离与策略默认值相同的字段,只保存用户真正修改过的值 + overrides = _strip_defaults(req.strategy_id, req.overrides, engine) + + strategy_config.save_override(_data_dir(request), req.strategy_id, overrides) + return {"ok": True} + + +def _strip_defaults(strategy_id: str, overrides: dict, engine) -> dict: + """剥离与策略默认值相同的字段,避免默认值被固化到 override 中。 + + 核心问题: 前端把策略的默认 basic_filter 全量发回后端保存, + 导致隐含的默认过滤条件 (如 market_cap_min, amount_min) 被写入 override 文件。 + 即使前端 UI 不展示这些字段,它们仍会在策略运行时生效。 + """ + s = engine.get(strategy_id) + result = dict(overrides) + + # 处理 basic_filter: 只保留与策略默认值不同的键 + bf = result.get("basic_filter") + if bf and isinstance(bf, dict): + default_bf = s.basic_filter if s else {} + stripped_bf = {} + for k, v in bf.items(): + default_val = default_bf.get(k) + # 保留与默认值不同的键,以及没有默认值的键 + if k not in default_bf or v != default_val: + stripped_bf[k] = v + if stripped_bf: + result["basic_filter"] = stripped_bf + else: + del result["basic_filter"] + + return result + + +@router.delete("/config/{strategy_id}") +def reset_config(strategy_id: str, request: Request): + strategy_config.delete_override(_data_dir(request), strategy_id) + return {"ok": True} + + +# ── AI 生成 ─────────────────────────────────────────────────────────── + +class BuildRequest(BaseModel): + """两步策略构建请求""" + step: int # 1 / 2 + # step1 字段 + name: str = "" + description: str = "" + direction: str = "long" + rules: str = "" + strategy_id: str = "" + # step2 字段 + current_code: str = "" + instruction: str = "" + + +@router.get("/ai/status") +def ai_status(request: Request): + """检查 AI 配置状态""" + from app.config import settings + from app import secrets_store + has_key = bool(secrets_store.get_ai_key()) + has_model = bool(settings.ai_model) + return {"configured": has_key and has_model, "has_key": has_key, "has_model": has_model} + + +@router.get("/{strategy_id}/source") +def get_strategy_source(strategy_id: str, request: Request): + """获取策略源文件内容(用于 AI 修改)""" + from pathlib import Path + + # 先查 StrategyEngine 获取文件路径 + engine = _get_engine(request) + try: + s = engine.get(strategy_id) + except ValueError: + raise HTTPException(status_code=404, detail=f"策略 {strategy_id} 不存在") + + path = s.file_path + if not path or not path.exists(): + raise HTTPException(status_code=404, detail="策略源文件不存在") + + return {"code": path.read_text(encoding="utf-8"), "source": s.source} + + +@router.post("/ai/test") +async def ai_test(request: Request): + """测试 AI 连通性 — 发送简单请求验证 Key 和模型""" + from app.config import settings + from app import secrets_store + from openai import AsyncOpenAI + + ai_key = secrets_store.get_ai_key() + if not ai_key: + return {"ok": False, "error": "未配置 API Key"} + + try: + client = AsyncOpenAI(api_key=ai_key, base_url=settings.ai_base_url) + resp = await client.chat.completions.create( + model=settings.ai_model, + messages=[{"role": "user", "content": "回复 OK"}], + max_tokens=5, + timeout=15, + ) + return {"ok": True, "model": resp.model, "usage": {"prompt": resp.usage.prompt_tokens, "completion": resp.usage.completion_tokens} if resp.usage else None} + except Exception as e: + return {"ok": False, "error": str(e)} + + +@router.post("/build") +async def build_strategy(req: BuildRequest, request: Request): + """两步策略构建。 + step1: name + description + direction + rules → 完整策略 + step2: current_code + instruction → 修改任意部分 + """ + gen = AIStrategyGenerator() + + if req.step == 1: + prompt = build_step1(req.name, req.description, req.direction, req.rules, req.strategy_id) + elif req.step == 2: + prompt = build_step2(req.current_code, req.instruction) + else: + raise HTTPException(status_code=400, detail=f"无效步骤: {req.step}") + + try: + result = await gen.generate(prompt) + except RuntimeError as e: + raise HTTPException(status_code=400, detail=str(e)) from e + return result + + + +@router.post("/ai/generate") +async def ai_generate(req: AIGenerateRequest, request: Request): + try: + gen = AIStrategyGenerator() + result = await gen.generate(req.prompt) + except RuntimeError as e: + raise HTTPException(status_code=400, detail=str(e)) from e + except Exception as e: + raise HTTPException(status_code=500, detail=f"AI生成失败: {e}") from e + return result + + +@router.post("/ai/save") +async def ai_save(req: AISaveRequest, request: Request): + data_dir = _data_dir(request) + out_dir = data_dir / "strategies" / "ai" + out_dir.mkdir(parents=True, exist_ok=True) + path = out_dir / f"{req.strategy_id}.py" + previous_code = path.read_text(encoding="utf-8") if path.exists() else None + path.write_text(req.code, encoding="utf-8") + + # 热重载,并确认保存的策略真的被引擎加载。 + engine = _get_engine(request) + engine.reload() + if not engine.has(req.strategy_id): + if previous_code is None: + path.unlink(missing_ok=True) + else: + path.write_text(previous_code, encoding="utf-8") + engine.reload() + raise HTTPException( + status_code=400, + detail=f"策略保存成功但加载失败: {req.strategy_id},请检查代码语法和 META.id 是否一致", + ) + return {"ok": True, "path": str(path)} + + +@router.delete("/{strategy_id}") +def delete_strategy(strategy_id: str, request: Request): + """删除自定义策略 — 清除 .py 文件 + overrides + 热重载。内置策略不可删除。""" + from pathlib import Path + + engine = _get_engine(request) + try: + s = engine.get(strategy_id) + except ValueError: + raise HTTPException(status_code=404, detail=f"策略 {strategy_id} 不存在") + + if s.source == "builtin": + raise HTTPException(status_code=403, detail="内置策略不可删除") + + # 删除策略文件 + if s.file_path and s.file_path.exists(): + s.file_path.unlink() + + # 删除 overrides + data_dir = _data_dir(request) + override_path = data_dir / "user_data" / "strategy_overrides" / f"{strategy_id}.json" + if override_path.exists(): + override_path.unlink() + + # 热重载 + engine.reload() + return {"ok": True} + + +# ── 监控 ───────────────────────────────────────────────────────────── + + +@router.post("/monitor/start") +def monitor_start(req: MonitorStartRequest, request: Request): + engine = _get_engine(request) + monitor = _get_monitor(request) + try: + s = engine.get(req.strategy_id) + except ValueError as e: + raise HTTPException(status_code=404, detail=str(e)) from e + + monitor.start(req.strategy_id, { + "entry_signals": s.entry_signals, + "exit_signals": s.exit_signals, + "alerts": s.alerts, + }) + return {"ok": True, "watching": list(monitor.watching.keys())} + + +@router.post("/monitor/stop/{strategy_id}") +def monitor_stop(strategy_id: str, request: Request): + monitor = _get_monitor(request) + monitor.stop(strategy_id) + return {"ok": True, "watching": list(monitor.watching.keys())} + + +@router.get("/monitor/status") +def monitor_status(request: Request): + monitor = _get_monitor(request) + return {"watching": list(monitor.watching.keys())} + + +# ── 热重载 ─────────────────────────────────────────────────────────── + + +@router.post("/reload") +def reload_strategies(request: Request): + engine = _get_engine(request) + engine.reload() + return {"ok": True, "count": len(engine.list_strategies())} diff --git a/backend/app/api/watchlist.py b/backend/app/api/watchlist.py new file mode 100644 index 0000000..183b875 --- /dev/null +++ b/backend/app/api/watchlist.py @@ -0,0 +1,202 @@ +"""自选股 API。""" +from __future__ import annotations + +import logging +import math +import time +from datetime import date + +import polars as pl +from fastapi import APIRouter, Query, Request +from pydantic import BaseModel + +from app.services import watchlist + +logger = logging.getLogger(__name__) + +router = APIRouter(prefix="/api/watchlist", tags=["watchlist"]) + + +class AddRequest(BaseModel): + symbol: str + note: str = "" + + +class BatchAddRequest(BaseModel): + symbols: list[str] + note: str = "" + + +@router.get("") +def list_all(): + return {"symbols": watchlist.list_symbols()} + + +@router.post("") +def add_one(req: AddRequest): + rows = watchlist.add(req.symbol, req.note) + return {"symbols": rows} + + +@router.post("/batch") +def add_batch(req: BatchAddRequest): + for sym in req.symbols: + watchlist.add(sym, req.note) + return {"symbols": watchlist.list_symbols(), "added": len(req.symbols)} + + +@router.delete("/{symbol}") +def remove_one(symbol: str): + rows = watchlist.remove(symbol) + return {"symbols": rows} + + +@router.delete("") +def clear_all(): + """清空自选列表。""" + count = watchlist.clear() + return {"removed": count} + + +# 自选页需要的列 +_WATCHLIST_COLS = [ + "symbol", "close", "change_pct", "change_amount", "amount", + "turnover_rate", + "amplitude", "annual_vol_20d", + "vol_ratio_5d", + "ma5", "ma10", "ma20", "ma60", + "vol_ma5", "vol_ma10", + "high_60d", "low_60d", + "rsi_6", "rsi_14", "rsi_24", + "macd_dif", "macd_dea", "macd_hist", + "kdj_k", "kdj_d", "kdj_j", + "boll_upper", "boll_lower", + "atr_14", + "momentum_5d", "momentum_10d", "momentum_20d", "momentum_30d", "momentum_60d", + "consecutive_limit_ups", "consecutive_limit_downs", + "signal_limit_up", "signal_limit_down", "signal_volume_surge", + "signal_ma_golden_5_20", "signal_macd_golden", "signal_n_day_high", + "signal_boll_breakout_upper", "signal_ma20_breakout", + "signal_ma_dead_5_20", "signal_macd_dead", "signal_n_day_low", + "signal_boll_breakdown_lower", "signal_ma20_breakdown", +] + + +@router.get("/enriched") +def watchlist_enriched( + request: Request, + ext_columns: str | None = Query(None, description="逗号分隔的 ext 列: config_id.field_name"), +): + """自选股 enriched 数据 — 直接从 enriched 最新日读取, 无即时计算。 + + ext_columns 参数示例: "industry_rating.score,fund_flow.net_inflow" + 会动态 LEFT JOIN 对应的 ext_{config_id} DuckDB view。 + """ + t0 = time.perf_counter() + + repo = request.app.state.repo + symbols = [r["symbol"] for r in watchlist.list_symbols()] + if not symbols: + return {"rows": [], "as_of": None, "elapsed_ms": 0} + + df_e, cache_date = repo.get_enriched_latest() + if df_e.is_empty(): + return {"rows": [], "as_of": None, "elapsed_ms": 0} + + # 按 symbol 过滤 + df = df_e.filter(pl.col("symbol").is_in(symbols)) + if df.is_empty(): + return {"rows": [], "as_of": str(cache_date) if cache_date else None, "elapsed_ms": 0} + + # JOIN instruments 取 name + float_shares + df_i = repo.get_instruments() + if not df_i.is_empty() and "name" in df_i.columns: + inst_cols = [c for c in ["symbol", "name", "float_shares"] if c in df_i.columns] + df = df.join(df_i.select(inst_cols), on="symbol", how="left") + + # 选择内置需要的列 + keep = [c for c in _WATCHLIST_COLS + ["name", "float_shares"] if c in df.columns] + df = df.select(keep) + + # 动态 JOIN 扩展数据表 + ext_specs = _parse_ext_columns(ext_columns) if ext_columns else [] + if ext_specs: + db = repo.store.db + data_dir = repo.store.data_dir + from app.services.ext_data import ExtConfigStore + from app.api.ext_data import _read_ext_dataframe + + ext_store = ExtConfigStore(data_dir) + configs = {c.id: c for c in ext_store.load_all()} + + for config_id, field_name in ext_specs: + view_name = f"ext_{config_id}" + ext_col_name = f"{config_id}__{field_name}" + try: + # 扩展时序数据必须只取最新分区;否则一个 symbol 会按历史分区数被 JOIN 放大。 + cfg = configs.get(config_id) + if cfg: + ext_df, _ = _read_ext_dataframe(cfg, data_dir) + else: + ext_df = pl.from_arrow(db.query( + f"SELECT symbol, \"{field_name}\" FROM {view_name}" + ).arrow()) + if not ext_df.is_empty() and "symbol" in ext_df.columns: + ext_df = ( + ext_df + .select(["symbol", field_name]) + .unique(subset=["symbol"], keep="last") + .rename({field_name: ext_col_name}) + ) + df = df.join(ext_df.select(["symbol", ext_col_name]), on="symbol", how="left") + except Exception: + # view 不存在或字段不存在,尝试直接读 parquet + cfg = configs.get(config_id) + if cfg: + try: + ext_df, _ = _read_ext_dataframe(cfg, data_dir) + if not ext_df.is_empty() and "symbol" in ext_df.columns and field_name in ext_df.columns: + ext_df = ( + ext_df + .select(["symbol", field_name]) + .unique(subset=["symbol"], keep="last") + .rename({field_name: ext_col_name}) + ) + df = df.join(ext_df, on="symbol", how="left") + except Exception as e2: + logger.debug("ext join fallback failed for %s.%s: %s", config_id, field_name, e2) + + # sanitize NaN / Inf + float_cols = [c for c in df.columns if df[c].dtype.is_float()] + if float_cols: + df = df.with_columns([ + pl.when(pl.col(c).is_nan() | pl.col(c).is_infinite()) + .then(None) + .otherwise(pl.col(c)) + .alias(c) + for c in float_cols + ]) + + # 按自选添加顺序(新加的在前)重排行 + order_map = {s: i for i, s in enumerate(symbols)} + df = df.with_columns(pl.col("symbol").map_elements(lambda s: order_map.get(s, len(symbols)), return_dtype=pl.Int32).alias("_sort_order")) + df = df.sort("_sort_order").drop("_sort_order") + + rows = df.to_dicts() + elapsed = (time.perf_counter() - t0) * 1000 + return {"rows": rows, "as_of": str(cache_date) if cache_date else None, "elapsed_ms": elapsed} + + +def _parse_ext_columns(ext_columns: str) -> list[tuple[str, str]]: + """解析 'config_id1.field1,config_id2.field2' 为 [(config_id, field_name), ...]""" + result = [] + for part in ext_columns.split(","): + part = part.strip() + if "." not in part: + continue + config_id, field_name = part.split(".", 1) + config_id = config_id.strip() + field_name = field_name.strip() + if config_id and field_name: + result.append((config_id, field_name)) + return result diff --git a/backend/app/backtest/__init__.py b/backend/app/backtest/__init__.py new file mode 100644 index 0000000..adfd49b --- /dev/null +++ b/backend/app/backtest/__init__.py @@ -0,0 +1,4 @@ +"""回测模块 — 因子回测 + 策略回测 + 信号回测。 + +架构: BacktestEngine (共享) → FactorBacktestService / StrategyBacktestService +""" diff --git a/backend/app/backtest/engine.py b/backend/app/backtest/engine.py new file mode 100644 index 0000000..ad11712 --- /dev/null +++ b/backend/app/backtest/engine.py @@ -0,0 +1,1485 @@ +"""回测引擎 — 共享数据加载 + 撮合 + 统计计算。 + +纯 Polars/NumPy 实现,不依赖 pandas/vectorbt。 +""" +from __future__ import annotations + +import hashlib +import logging +import time +from collections import OrderedDict +from dataclasses import dataclass +from datetime import date +from typing import Callable + +logger = logging.getLogger(__name__) +from typing import Literal + +import numpy as np +import polars as pl + +from app.tickflow.repository import KlineRepository + +logger = logging.getLogger(__name__) + + +# ================================================================ +# 数据结构 +# ================================================================ + +@dataclass +class MatcherConfig: + matching: Literal["close_t", "open_t+1"] = "close_t" + fees_pct: float = 0.0002 + slippage_bps: float = 5.0 + stop_loss_pct: float | None = None + trailing_stop_pct: float | None = None + trailing_take_profit_activate_pct: float | None = None + trailing_take_profit_drawdown_pct: float | None = None + max_hold_days: int | None = None + max_positions: int = 10 + max_exposure_pct: float = 1.0 + score_min: float | None = None + score_max: float | None = None + initial_capital: float = 1_000_000.0 + position_sizing: Literal["equal", "score_weight"] = "equal" + + +@dataclass +class TradeRecord: + symbol: str + entry_date: date + exit_date: date + entry_price: float + exit_price: float + pnl_pct: float + duration: int + exit_reason: str # "signal" | "stop_loss" | "trailing_stop" | "trailing_take_profit" | "max_hold" | "end" + name: str = "" + shares: float = 0.0 + lots: float = 0.0 + position_pct: float = 0.0 + entry_value: float = 0.0 + exit_value: float = 0.0 + pnl_amount: float = 0.0 + entry_score: float | None = None + entry_signal_date: date | str | None = None + exit_signal_date: date | str | None = None + blocked_exit_days: int = 0 + + +@dataclass +class SimResult: + equity_curve: list[dict] # [{date, value}] + drawdown_curve: list[dict] # [{date, value}] + trades: list[TradeRecord] + per_symbol_stats: list[dict] + stats: dict + + +# ================================================================ +# PanelCache — 避免重复 scan_parquet + compute_all +# ================================================================ + +class _CacheEntry: + __slots__ = ("df", "ts") + + def __init__(self, df: pl.DataFrame, ts: float): + self.df = df + self.ts = ts + + +class PanelCache: + """LRU + TTL 数据面板缓存。""" + + def __init__(self, max_size: int = 2, ttl_seconds: int = 180): + self._cache: OrderedDict[str, _CacheEntry] = OrderedDict() + self._max_size = max_size + self._ttl = ttl_seconds + + def get_or_compute( + self, + symbols: list[str] | None, + start: date, + end: date, + columns: list[str] | None, + compute_fn, + ) -> pl.DataFrame: + key = self._make_key(symbols, start, end, columns) + now = time.monotonic() + + if key in self._cache: + entry = self._cache[key] + if now - entry.ts < self._ttl: + self._cache.move_to_end(key) + return entry.df + del self._cache[key] + + df = compute_fn(symbols, start, end, columns) + self._cache[key] = _CacheEntry(df=df, ts=now) + if len(self._cache) > self._max_size: + self._cache.popitem(last=False) + return df + + def invalidate(self) -> None: + self._cache.clear() + + @staticmethod + def _make_key(symbols: list[str] | None, start: date, end: date, columns: list[str] | None) -> str: + if symbols is None: + h = "all" + else: + h = hashlib.md5(",".join(sorted(symbols)).encode()).hexdigest()[:12] + cols = "all" if columns is None else hashlib.md5(",".join(sorted(columns)).encode()).hexdigest()[:8] + return f"{h}:{start}:{end}:{cols}" + + +# ================================================================ +# BacktestEngine +# ================================================================ + +class BacktestEngine: + """回测引擎 — 数据加载 + 撮合模拟 + 统计计算。""" + + def __init__(self, repo: KlineRepository) -> None: + self.repo = repo + self._cache = PanelCache() + + # ── 数据加载 ────────────────────────────────────── + + def load_panel( + self, + symbols: list[str] | None, + start: date, + end: date, + columns: list[str] | None = None, + ) -> pl.DataFrame: + """加载 enriched 数据面板,带缓存。""" + return self._cache.get_or_compute(symbols, start, end, columns, self._load_panel_inner) + + def _load_panel_inner( + self, + symbols: list[str] | None, + start: date, + end: date, + columns: list[str] | None = None, + ) -> pl.DataFrame: + t0 = time.perf_counter() + + # 近期区间优先复用 repository 的预计算 enriched 历史缓存,避免重复 scan_parquet + compute_all。 + try: + if self.repo is not None and hasattr(self.repo, "get_enriched_range"): + cached = self.repo.get_enriched_range(start, end, symbols=symbols, columns=columns) + if cached is not None and not cached.is_empty(): + elapsed = (time.perf_counter() - t0) * 1000 + logger.info("load_panel(cache): %.0fms, %d rows, %d columns", elapsed, len(cached), len(cached.columns)) + return cached + except Exception as e: # noqa: BLE001 + logger.debug("backtest load panel cache miss: %s", e) + + enriched_glob = str(self.repo.store.data_dir / "kline_daily_enriched" / "**" / "*.parquet") + + try: + lf = pl.scan_parquet(enriched_glob) + if symbols is not None: + lf = lf.filter(pl.col("symbol").is_in(symbols)) + if columns is not None: + available = set(lf.collect_schema().names()) + selected = [c for c in columns if c in available] + if "symbol" not in selected and "symbol" in available: + selected.insert(0, "symbol") + if "date" not in selected and "date" in available: + selected.insert(1, "date") + lf = lf.select(selected) + df = ( + lf.filter( + (pl.col("date") >= start) + & (pl.col("date") <= end) + ) + .sort(["symbol", "date"]) + .collect(streaming=True) + ) + except Exception as e: + logger.warning("backtest load panel failed: %s", e) + return pl.DataFrame() + + if df.is_empty(): + return df + + if columns is not None: + elapsed = (time.perf_counter() - t0) * 1000 + logger.info("load_panel: %.0fms, %d rows, %d columns", elapsed, len(df), len(df.columns)) + return df + + from app.indicators.pipeline import compute_all + instruments = self.repo.get_instruments() + df = compute_all(df, instruments=instruments) + if not instruments.is_empty() and "name" not in df.columns: + inst_cols = [c for c in ["symbol", "name"] if c in instruments.columns] + if len(inst_cols) == 2: + df = df.join( + instruments.select(inst_cols).unique(subset=["symbol"]), + on="symbol", + how="left", + ) + + elapsed = (time.perf_counter() - t0) * 1000 + logger.info("load_panel: %.0fms, %d rows", elapsed, len(df)) + return df + + # ── 撮合模拟 ────────────────────────────────────── + + def simulate( + self, + panel: pl.DataFrame, + entries: pl.Series | None, + exits: pl.Series | None, + config: MatcherConfig, + ) -> SimResult: + """纯 NumPy 撮合模拟 — 逐 symbol 状态机。""" + if panel.is_empty(): + return self._empty_result() + + n = len(panel) + panel_dates = panel["date"].to_numpy() + panel_symbols = panel["symbol"].to_numpy() + + # 构建信号数组 + ent = np.zeros(n, dtype=bool) + ext = np.zeros(n, dtype=bool) + if entries is not None and len(entries) == n: + ent = entries.to_numpy().astype(bool) + if exits is not None and len(exits) == n: + ext = exits.to_numpy().astype(bool) + + if not ent.any(): + return self._empty_result() + + # T+1: 信号右移 1 天 + 使用开盘价撮合 + if config.matching == "open_t+1": + price_col = "open" + ent_s = np.zeros(n, dtype=bool) + ext_s = np.zeros(n, dtype=bool) + ent_s[1:] = ent[:-1] + ext_s[1:] = ext[:-1] + ent = ent_s + ext = ext_s + else: + price_col = "close" + + prices = panel[price_col].to_numpy() + close_prices = panel["close"].to_numpy() + + # 逐 symbol 撮合 + trades: list[TradeRecord] = [] + unique_symbols = np.unique(panel_symbols) + + for sym in unique_symbols: + mask = panel_symbols == sym + sym_ent = ent[mask] + sym_ext = ext[mask] + sym_prices = prices[mask] + sym_close = close_prices[mask] + sym_dates = panel_dates[mask] + + holding = False + entry_idx = -1 + entry_price = 0.0 + hold_days = 0 + + for i in range(len(sym_ent)): + if not holding: + if sym_ent[i]: + holding = True + entry_idx = i + entry_price = float(sym_prices[i]) + hold_days = 0 + else: + hold_days += 1 + exit_triggered = False + exit_reason = "" + + # 止损 — 用当日 close 检测 + if config.stop_loss_pct is not None: + pnl = (float(sym_close[i]) - entry_price) / entry_price + if pnl <= -abs(config.stop_loss_pct): + exit_triggered = True + exit_reason = "stop_loss" + + # 最大持仓天数 + if not exit_triggered and config.max_hold_days is not None: + if hold_days >= config.max_hold_days: + exit_triggered = True + exit_reason = "max_hold" + + # 信号退出 + if not exit_triggered and sym_ext[i]: + exit_triggered = True + exit_reason = "signal" + + if exit_triggered: + exit_price = float(sym_prices[i]) + pnl_pct = (exit_price - entry_price) / entry_price if entry_price > 0 else 0.0 + fee_cost = config.fees_pct * 2 + config.slippage_bps / 10000.0 * 2 + pnl_pct -= fee_cost + + e_date = sym_dates[entry_idx] + x_date = sym_dates[i] + trades.append(TradeRecord( + symbol=str(sym), + entry_date=e_date.item() if hasattr(e_date, "item") else e_date, + exit_date=x_date.item() if hasattr(x_date, "item") else x_date, + entry_price=round(entry_price, 4), + exit_price=round(exit_price, 4), + pnl_pct=round(pnl_pct, 6), + duration=int(hold_days), + exit_reason=exit_reason, + )) + holding = False + + # 净值曲线: 按出场日期归集收益 + all_dates_sorted = np.sort(np.unique(panel_dates)) + equity_curve, drawdown_curve = self._build_curves(trades, all_dates_sorted, config.initial_capital) + + # 统计 + date_min = panel_dates.min() + date_max = panel_dates.max() + d_min = date_min.item() if hasattr(date_min, "item") else date_min + d_max = date_max.item() if hasattr(date_max, "item") else date_max + stats = self._calc_stats(trades, config.initial_capital, d_min, d_max) + per_symbol = self._calc_per_symbol(trades) + + return SimResult( + equity_curve=equity_curve, + drawdown_curve=drawdown_curve, + trades=trades, + per_symbol_stats=per_symbol, + stats=stats, + ) + + def simulate_independent_candidates( + self, + panel: pl.DataFrame, + entries: pl.Series | None, + exits: pl.Series | None, + config: MatcherConfig, + progress_cb: "Callable[[dict], None] | None" = None, + cancel_event: "threading.Event | None" = None, + ) -> SimResult: + """全量候选独立执行:每个买入信号都是独立样本, 不受资金/仓位限制。""" + if panel.is_empty(): + return self._empty_result() + + n = len(panel) + panel_dates = panel["date"].to_numpy() + panel_symbols = panel["symbol"].to_numpy() + + ent_raw = np.zeros(n, dtype=bool) + ext_raw = np.zeros(n, dtype=bool) + if entries is not None and len(entries) == n: + ent_raw = entries.to_numpy().astype(bool) + if exits is not None and len(exits) == n: + ext_raw = exits.to_numpy().astype(bool) + n_candidates = int(ent_raw.sum()) + if n_candidates <= 0: + return self._empty_result() + + entry_signal_dates = np.array([None] * n, dtype=object) + exit_signal_dates = np.array([None] * n, dtype=object) + if config.matching == "open_t+1": + price_col = "open" + ent = np.zeros(n, dtype=bool) + ext = np.zeros(n, dtype=bool) + same_prev_symbol = panel_symbols[1:] == panel_symbols[:-1] + ent[1:] = ent_raw[:-1] & same_prev_symbol + ext[1:] = ext_raw[:-1] & same_prev_symbol + for idx in np.flatnonzero(ent): + entry_signal_dates[idx] = self._date_str(panel_dates[idx - 1]) + for idx in np.flatnonzero(ext): + exit_signal_dates[idx] = self._date_str(panel_dates[idx - 1]) + else: + price_col = "close" + ent = ent_raw + ext = ext_raw + for idx in np.flatnonzero(ent): + entry_signal_dates[idx] = self._date_str(panel_dates[idx]) + for idx in np.flatnonzero(ext): + exit_signal_dates[idx] = self._date_str(panel_dates[idx]) + + prices = panel[price_col].to_numpy() + open_prices = panel["open"].to_numpy() + high_prices = panel["high"].to_numpy() if "high" in panel.columns else open_prices + low_prices = panel["low"].to_numpy() + close_prices = panel["close"].to_numpy() + has_volume = "volume" in panel.columns + volumes = panel["volume"].fill_null(0).to_numpy() if has_volume else np.ones(n, dtype=float) + names = panel["name"].fill_null("").to_numpy() if "name" in panel.columns else np.array([""] * n) + scores = panel["score"].fill_null(0).to_numpy() if "score" in panel.columns else np.zeros(n, dtype=float) + trade_scores = scores.copy() + if config.matching == "open_t+1": + trade_scores[1:] = np.where(panel_symbols[1:] == panel_symbols[:-1], scores[:-1], trade_scores[1:]) + limit_up_flags = ( + panel["signal_limit_up"].fill_null(False).to_numpy().astype(bool) + if "signal_limit_up" in panel.columns else np.zeros(n, dtype=bool) + ) + limit_down_flags = ( + panel["signal_limit_down"].fill_null(False).to_numpy().astype(bool) + if "signal_limit_down" in panel.columns else np.zeros(n, dtype=bool) + ) + + symbol_rows: dict[str, list[int]] = {} + row_pos_in_symbol = np.zeros(n, dtype=int) + for i, sym_value in enumerate(panel_symbols): + sym = str(sym_value) + rows = symbol_rows.setdefault(sym, []) + row_pos_in_symbol[i] = len(rows) + rows.append(i) + + buy_cost_pct = config.fees_pct + config.slippage_bps / 10000.0 + sell_cost_pct = config.fees_pct + config.slippage_bps / 10000.0 + score_min = getattr(config, "score_min", None) + score_max = getattr(config, "score_max", None) + close_mode = config.matching == "close_t" + trades: list[TradeRecord] = [] + execution_stats: dict[str, int] = { + "buy_invalid_price": 0, + "buy_suspended": 0, + "buy_limit_up": 0, + "buy_score_filter": 0, + "buy_no_next_bar": max(n_candidates - int(ent.sum()), 0), + "sell_invalid_price": 0, + "sell_suspended": 0, + "sell_limit_down": 0, + "sell_no_future": 0, + "pending_exit": 0, + } + + def _count(key: str) -> None: + execution_stats[key] = execution_stats.get(key, 0) + 1 + + def _valid_price(value) -> bool: + try: + v = float(value) + except (TypeError, ValueError): + return False + return v > 0 and np.isfinite(v) + + def _is_suspended(idx: int) -> bool: + o = float(open_prices[idx]) + h = float(high_prices[idx]) + l = float(low_prices[idx]) + c = float(close_prices[idx]) + valid_bar = any(_valid_price(x) for x in (o, h, l, c)) + if not valid_bar: + return True + if has_volume and float(volumes[idx] or 0) <= 0: + same_price = max(o, h, l, c) - min(o, h, l, c) <= max(abs(c) * 1e-4, 0.01) + if same_price: + return True + return False + + def _is_one_price_limit(idx: int, direction: str) -> bool: + if _is_suspended(idx): + return False + o = float(open_prices[idx]) + h = float(high_prices[idx]) + l = float(low_prices[idx]) + c = float(close_prices[idx]) + if not all(_valid_price(x) for x in (o, h, l, c)): + return False + same_price = max(o, h, l, c) - min(o, h, l, c) <= max(abs(c) * 1e-4, 0.01) + if direction == "up": + return bool(limit_up_flags[idx]) and same_price + return bool(limit_down_flags[idx]) and same_price + + def _can_buy(idx: int) -> tuple[bool, str]: + if _is_suspended(idx): + return False, "buy_suspended" + if not _valid_price(prices[idx]): + return False, "buy_invalid_price" + if _is_one_price_limit(idx, "up"): + return False, "buy_limit_up" + return True, "" + + def _can_sell(idx: int, exit_price_override: float | None = None) -> tuple[bool, str]: + if _is_suspended(idx): + return False, "sell_suspended" + exit_price = exit_price_override if exit_price_override is not None else prices[idx] + if not _valid_price(exit_price): + return False, "sell_invalid_price" + if _is_one_price_limit(idx, "down"): + return False, "sell_limit_down" + return True, "" + + def _risk_exit(pos: dict, idx: int) -> tuple[str | None, float | None]: + if pos.get("pending_exit_reason") or pos.get("entry_idx") == idx: + return None, None + entry_price = float(pos["entry_price"]) + if entry_price <= 0: + return None, None + open_price = float(open_prices[idx]) + low_price = float(low_prices[idx]) + peak_price = float(pos.get("max_high", entry_price)) + risk_lines: list[tuple[float, str]] = [] + + if config.stop_loss_pct is not None: + risk_lines.append((entry_price * (1 - abs(config.stop_loss_pct)), "stop_loss")) + if config.trailing_stop_pct is not None and peak_price > 0: + risk_lines.append((peak_price * (1 - abs(config.trailing_stop_pct)), "trailing_stop")) + + activate_pct = getattr(config, "trailing_take_profit_activate_pct", None) + drawdown_pct = getattr(config, "trailing_take_profit_drawdown_pct", None) + if activate_pct is not None and drawdown_pct is not None and peak_price > entry_price: + peak_profit = peak_price / entry_price - 1 + if peak_profit >= abs(float(activate_pct)): + risk_lines.append((entry_price * (1 + peak_profit - abs(float(drawdown_pct))), "trailing_take_profit")) + + risk_lines = [(line, reason) for line, reason in risk_lines if _valid_price(line)] + if not risk_lines: + return None, None + stop_price, reason = max(risk_lines, key=lambda item: item[0]) + if _valid_price(open_price) and open_price <= stop_price: + return reason, open_price + if _valid_price(low_price) and low_price <= stop_price: + return reason, stop_price + return None, None + + def _try_close(pos: dict, idx: int, reason: str, signal_date: str, exit_price_override: float | None = None) -> bool: + ok, block_reason = _can_sell(idx, exit_price_override) + if not ok: + if not pos.get("pending_exit_reason"): + pos["pending_exit_reason"] = reason + pos["pending_exit_signal_date"] = signal_date + _count("pending_exit") + pos["blocked_exit_days"] = int(pos.get("blocked_exit_days", 0)) + 1 + _count(block_reason) + return False + + exit_price = float(exit_price_override) if exit_price_override is not None else float(prices[idx]) + shares = 100.0 + entry_value = shares * float(pos["entry_price"]) * (1 + buy_cost_pct) + exit_value = shares * exit_price * (1 - sell_cost_pct) + pnl_amount = exit_value - entry_value + pnl_pct = pnl_amount / entry_value if entry_value > 0 else 0.0 + trades.append(TradeRecord( + symbol=str(pos["symbol"]), + name=str(pos.get("name", "")), + entry_date=pos["entry_date"], + exit_date=self._date_str(panel_dates[idx]), + entry_price=round(float(pos["entry_price"]), 4), + exit_price=round(exit_price, 4), + pnl_pct=round(float(pnl_pct), 6), + duration=int(pos["hold_days"]), + exit_reason=reason, + shares=shares, + lots=1.0, + position_pct=0.0, + entry_value=round(float(entry_value), 2), + exit_value=round(float(exit_value), 2), + pnl_amount=round(float(pnl_amount), 2), + entry_score=round(float(pos["entry_score"]), 2) if pos.get("entry_score") is not None else None, + entry_signal_date=pos.get("entry_signal_date"), + exit_signal_date=signal_date, + blocked_exit_days=int(pos.get("blocked_exit_days", 0)), + )) + return True + + candidate_indices = np.flatnonzero(ent) + for seq, entry_idx in enumerate(candidate_indices, start=1): + if cancel_event is not None and cancel_event.is_set(): + logger.info("全量模拟被用户取消 (第 %d/%d 个候选)", seq, len(candidate_indices)) + break + if progress_cb is not None and (seq == 1 or seq % 500 == 0): + try: + progress_cb({ + "day": seq, + "total": len(candidate_indices), + "date": self._date_str(panel_dates[entry_idx]), + "equity": 0, + }) + except Exception: + pass + + ok, block_reason = _can_buy(entry_idx) + if not ok: + _count(block_reason) + continue + score = float(trade_scores[entry_idx] or 0.0) + if score_min is not None and score < score_min: + _count("buy_score_filter") + continue + if score_max is not None and score > score_max: + _count("buy_score_filter") + continue + + sym = str(panel_symbols[entry_idx]) + rows = symbol_rows.get(sym, []) + start_pos = int(row_pos_in_symbol[entry_idx]) + if start_pos >= len(rows): + _count("sell_no_future") + continue + + entry_price = float(prices[entry_idx]) + pos = { + "symbol": sym, + "name": str(names[entry_idx] or ""), + "entry_idx": entry_idx, + "entry_date": self._date_str(panel_dates[entry_idx]), + "entry_signal_date": entry_signal_dates[entry_idx] or self._date_str(panel_dates[entry_idx]), + "entry_price": entry_price, + "entry_score": score, + "hold_days": 0, + "max_high": entry_price, + "pending_exit_reason": None, + "pending_exit_signal_date": None, + "blocked_exit_days": 0, + } + hi = float(high_prices[entry_idx]) + if _valid_price(hi): + pos["max_high"] = max(float(pos["max_high"]), hi) + + closed = False + last_idx = entry_idx + for idx in rows[start_pos + 1:]: + last_idx = idx + pos["hold_days"] = int(pos["hold_days"]) + 1 + d_str = self._date_str(panel_dates[idx]) + + def _scheduled_reason() -> tuple[str | None, str]: + if pos.get("pending_exit_reason"): + return str(pos["pending_exit_reason"]), str(pos.get("pending_exit_signal_date") or d_str) + if config.max_hold_days is not None and pos["hold_days"] >= config.max_hold_days: + return "max_hold", d_str + if ext[idx]: + return "signal", str(exit_signal_dates[idx] or d_str) + if idx == rows[-1]: + return "end", d_str + return None, d_str + + if close_mode: + reason, override_price = _risk_exit(pos, idx) + if reason and _try_close(pos, idx, reason, d_str, override_price): + closed = True + break + reason, signal_date = _scheduled_reason() + if reason and _try_close(pos, idx, reason, signal_date): + closed = True + break + else: + reason, signal_date = _scheduled_reason() + if reason and _try_close(pos, idx, reason, signal_date): + closed = True + break + reason, override_price = _risk_exit(pos, idx) + if reason and _try_close(pos, idx, reason, d_str, override_price): + closed = True + break + + hi = float(high_prices[idx]) + if _valid_price(hi): + pos["max_high"] = max(float(pos.get("max_high", entry_price)), hi) + + if not closed: + if last_idx == entry_idx: + _count("sell_no_future") + elif not pos.get("pending_exit_reason"): + _try_close(pos, last_idx, "end", self._date_str(panel_dates[last_idx])) + + return self._calc_independent_candidate_result(trades, n_candidates, execution_stats) + + def simulate_portfolio( + self, + panel: pl.DataFrame, + entries: pl.Series | None, + exits: pl.Series | None, + config: MatcherConfig, + progress_cb: "Callable[[dict], None] | None" = None, + cancel_event: "threading.Event | None" = None, + ) -> SimResult: + """账户级组合回测:日线信号 → 成交约束 → 仓位/现金撮合。""" + if panel.is_empty(): + return self._empty_result() + + n = len(panel) + panel_dates = panel["date"].to_numpy() + panel_symbols = panel["symbol"].to_numpy() + + ent_raw = np.zeros(n, dtype=bool) + ext_raw = np.zeros(n, dtype=bool) + if entries is not None and len(entries) == n: + ent_raw = entries.to_numpy().astype(bool) + if exits is not None and len(exits) == n: + ext_raw = exits.to_numpy().astype(bool) + if not ent_raw.any(): + return self._empty_result() + + entry_signal_dates = np.array([None] * n, dtype=object) + exit_signal_dates = np.array([None] * n, dtype=object) + if config.matching == "open_t+1": + price_col = "open" + ent = np.zeros(n, dtype=bool) + ext = np.zeros(n, dtype=bool) + same_prev_symbol = panel_symbols[1:] == panel_symbols[:-1] + ent[1:] = ent_raw[:-1] & same_prev_symbol + ext[1:] = ext_raw[:-1] & same_prev_symbol + for idx in np.flatnonzero(ent): + entry_signal_dates[idx] = self._date_str(panel_dates[idx - 1]) + for idx in np.flatnonzero(ext): + exit_signal_dates[idx] = self._date_str(panel_dates[idx - 1]) + else: + price_col = "close" + ent = ent_raw + ext = ext_raw + for idx in np.flatnonzero(ent): + entry_signal_dates[idx] = self._date_str(panel_dates[idx]) + for idx in np.flatnonzero(ext): + exit_signal_dates[idx] = self._date_str(panel_dates[idx]) + + prices = panel[price_col].to_numpy() + open_prices = panel["open"].to_numpy() + high_prices = panel["high"].to_numpy() if "high" in panel.columns else open_prices + low_prices = panel["low"].to_numpy() + close_prices = panel["close"].to_numpy() + has_volume = "volume" in panel.columns + volumes = panel["volume"].fill_null(0).to_numpy() if has_volume else np.ones(n, dtype=float) + names = ( + panel["name"].fill_null("").to_numpy() + if "name" in panel.columns else np.array([""] * n) + ) + scores = ( + panel["score"].fill_null(0).to_numpy() + if "score" in panel.columns else np.zeros(n, dtype=float) + ) + trade_scores = scores.copy() + if config.matching == "open_t+1": + trade_scores[1:] = np.where(panel_symbols[1:] == panel_symbols[:-1], scores[:-1], trade_scores[1:]) + limit_up_flags = ( + panel["signal_limit_up"].fill_null(False).to_numpy().astype(bool) + if "signal_limit_up" in panel.columns else np.zeros(n, dtype=bool) + ) + limit_down_flags = ( + panel["signal_limit_down"].fill_null(False).to_numpy().astype(bool) + if "signal_limit_down" in panel.columns else np.zeros(n, dtype=bool) + ) + + date_to_indices: dict[str, list[int]] = {} + for i, d in enumerate(panel_dates): + d_str = self._date_str(d) + date_to_indices.setdefault(d_str, []).append(i) + all_dates = sorted(date_to_indices.keys()) + if not all_dates: + return self._empty_result() + + buy_cost_pct = config.fees_pct + config.slippage_bps / 10000.0 + sell_cost_pct = config.fees_pct + config.slippage_bps / 10000.0 + cash = float(config.initial_capital) + peak = cash + max_positions = max(int(config.max_positions), 0) + max_exposure_pct = min(max(float(getattr(config, "max_exposure_pct", 1.0)), 0.0), 1.0) + score_min = getattr(config, "score_min", None) + score_max = getattr(config, "score_max", None) + positions: dict[str, dict] = {} + last_close: dict[str, float] = {} + trades: list[TradeRecord] = [] + equity_curve: list[dict] = [] + drawdown_curve: list[dict] = [] + execution_stats: dict[str, int] = { + "buy_invalid_price": 0, + "buy_suspended": 0, + "buy_limit_up": 0, + "buy_no_slot": 0, + "buy_cash": 0, + "buy_lot_size": 0, + "buy_same_day_reentry": 0, + "buy_exposure": 0, + "buy_score_filter": 0, + "sell_invalid_price": 0, + "sell_suspended": 0, + "sell_limit_down": 0, + "pending_exit": 0, + } + + def _count(key: str) -> None: + execution_stats[key] = execution_stats.get(key, 0) + 1 + + def _valid_price(value) -> bool: + try: + v = float(value) + except (TypeError, ValueError): + return False + return v > 0 and np.isfinite(v) + + def _market_value() -> float: + value = 0.0 + for pos in positions.values(): + mark = last_close.get(pos["symbol"], pos["entry_price"]) + value += pos["shares"] * mark + return value + + def _is_suspended(idx: int) -> bool: + o = float(open_prices[idx]) + h = float(high_prices[idx]) + l = float(low_prices[idx]) + c = float(close_prices[idx]) + valid_bar = any(_valid_price(x) for x in (o, h, l, c)) + if not valid_bar: + return True + if has_volume and float(volumes[idx] or 0) <= 0: + same_price = max(o, h, l, c) - min(o, h, l, c) <= max(abs(c) * 1e-4, 0.01) + if same_price: + return True + return False + + def _is_one_price_limit(idx: int, direction: str) -> bool: + if _is_suspended(idx): + return False + o = float(open_prices[idx]) + h = float(high_prices[idx]) + l = float(low_prices[idx]) + c = float(close_prices[idx]) + if not all(_valid_price(x) for x in (o, h, l, c)): + return False + same_price = max(o, h, l, c) - min(o, h, l, c) <= max(abs(c) * 1e-4, 0.01) + if direction == "up": + return bool(limit_up_flags[idx]) and same_price + return bool(limit_down_flags[idx]) and same_price + + def _can_buy(idx: int) -> tuple[bool, str]: + if _is_suspended(idx): + return False, "buy_suspended" + if not _valid_price(prices[idx]): + return False, "buy_invalid_price" + if _is_one_price_limit(idx, "up"): + return False, "buy_limit_up" + return True, "" + + def _can_sell(idx: int, exit_price_override: float | None = None) -> tuple[bool, str]: + if _is_suspended(idx): + return False, "sell_suspended" + exit_price = exit_price_override if exit_price_override is not None else prices[idx] + if not _valid_price(exit_price): + return False, "sell_invalid_price" + if _is_one_price_limit(idx, "down"): + return False, "sell_limit_down" + return True, "" + + def _mark_pending(sym: str, reason: str, signal_date: str) -> None: + pos = positions[sym] + if not pos.get("pending_exit_reason"): + pos["pending_exit_reason"] = reason + pos["pending_exit_signal_date"] = signal_date + _count("pending_exit") + pos["blocked_exit_days"] = int(pos.get("blocked_exit_days", 0)) + 1 + + def _sell( + sym: str, + idx: int, + reason: str, + signal_date: str, + sold_today: set[str], + exit_price_override: float | None = None, + ) -> None: + nonlocal cash + pos = positions.pop(sym) + exit_price = float(exit_price_override) if exit_price_override is not None else float(prices[idx]) + exit_value = pos["shares"] * exit_price * (1 - sell_cost_pct) + cash += exit_value + pnl_amount = exit_value - pos["entry_value"] + pnl_pct = (exit_value - pos["entry_value"]) / pos["entry_value"] if pos["entry_value"] > 0 else 0.0 + sold_today.add(sym) + trades.append(TradeRecord( + symbol=sym, + name=pos.get("name", ""), + entry_date=pos["entry_date"], + exit_date=self._date_str(panel_dates[idx]), + entry_price=round(float(pos["entry_price"]), 4), + exit_price=round(exit_price, 4), + pnl_pct=round(float(pnl_pct), 6), + duration=int(pos["hold_days"]), + exit_reason=reason, + shares=round(float(pos["shares"]), 4), + lots=round(float(pos["lots"]), 2), + position_pct=round(float(pos.get("position_pct", 0.0)), 6), + entry_value=round(float(pos["entry_value"]), 2), + exit_value=round(float(exit_value), 2), + pnl_amount=round(float(pnl_amount), 2), + entry_score=round(float(pos["entry_score"]), 2) if pos.get("entry_score") is not None else None, + entry_signal_date=pos.get("entry_signal_date"), + exit_signal_date=signal_date, + blocked_exit_days=int(pos.get("blocked_exit_days", 0)), + )) + + def _try_sell( + sym: str, + idx: int | None, + reason: str, + signal_date: str, + sold_today: set[str], + exit_price_override: float | None = None, + ) -> bool: + if idx is None: + _mark_pending(sym, reason, signal_date) + _count("sell_suspended") + return False + ok, block_reason = _can_sell(idx, exit_price_override) + if not ok: + _mark_pending(sym, reason, signal_date) + _count(block_reason) + return False + _sell(sym, idx, reason, signal_date, sold_today, exit_price_override) + return True + + def _process_scheduled_exits( + d_idx: int, + d_str: str, + row_by_symbol: dict[str, int], + sold_today: set[str], + ) -> None: + for sym in list(positions.keys()): + pos = positions.get(sym) + if pos is None: + continue + idx = row_by_symbol.get(sym) + reason = "" + signal_date = d_str + if pos.get("pending_exit_reason"): + reason = str(pos["pending_exit_reason"]) + signal_date = str(pos.get("pending_exit_signal_date") or d_str) + elif config.max_hold_days is not None and pos["hold_days"] >= config.max_hold_days: + reason = "max_hold" + elif idx is not None and ext[idx]: + reason = "signal" + signal_date = str(exit_signal_dates[idx] or d_str) + elif d_idx == len(all_dates) - 1: + reason = "end" + if reason: + _try_sell(sym, idx, reason, signal_date, sold_today) + + def _process_risk_exits(d_str: str, row_by_symbol: dict[str, int], sold_today: set[str]) -> None: + for sym in list(positions.keys()): + pos = positions.get(sym) + if pos is None or pos.get("pending_exit_reason"): + continue + if pos.get("entry_date") == d_str: + continue + idx = row_by_symbol.get(sym) + if idx is None or pos["entry_price"] <= 0: + continue + open_price = float(open_prices[idx]) + low_price = float(low_prices[idx]) + entry_price = float(pos["entry_price"]) + peak_price = float(pos.get("max_high", entry_price)) + risk_lines: list[tuple[float, str]] = [] + + if config.stop_loss_pct is not None: + risk_lines.append((entry_price * (1 - abs(config.stop_loss_pct)), "stop_loss")) + + if config.trailing_stop_pct is not None and peak_price > 0: + risk_lines.append((peak_price * (1 - abs(config.trailing_stop_pct)), "trailing_stop")) + + activate_pct = getattr(config, "trailing_take_profit_activate_pct", None) + drawdown_pct = getattr(config, "trailing_take_profit_drawdown_pct", None) + if activate_pct is not None and drawdown_pct is not None and peak_price > entry_price: + peak_profit = peak_price / entry_price - 1 + if peak_profit >= abs(float(activate_pct)): + take_profit_line = entry_price * (1 + peak_profit - abs(float(drawdown_pct))) + risk_lines.append((take_profit_line, "trailing_take_profit")) + + risk_lines = [(line, reason) for line, reason in risk_lines if _valid_price(line)] + if not risk_lines: + continue + stop_price, reason = max(risk_lines, key=lambda item: item[0]) + exit_price_override = None + if _valid_price(open_price) and open_price <= stop_price: + exit_price_override = open_price + elif _valid_price(low_price) and low_price <= stop_price: + exit_price_override = stop_price + if exit_price_override is not None: + _try_sell(sym, idx, reason, d_str, sold_today, exit_price_override) + + def _process_entries( + d_str: str, + idxs: list[int], + sold_today: set[str], + ) -> None: + nonlocal cash + if max_positions <= 0: + return + candidates: list[tuple[int, str, float]] = [] + for idx in idxs: + if not ent[idx]: + continue + sym = str(panel_symbols[idx]) + if sym in positions: + continue + if sym in sold_today: + _count("buy_same_day_reentry") + continue + ok, block_reason = _can_buy(idx) + if not ok: + _count(block_reason) + continue + score = float(trade_scores[idx] or 0.0) + if score_min is not None and score < score_min: + _count("buy_score_filter") + continue + if score_max is not None and score > score_max: + _count("buy_score_filter") + continue + candidates.append((idx, sym, score)) + if not candidates: + return + candidates.sort(key=lambda x: x[2], reverse=True) + + slots = max_positions - len(positions) + if slots <= 0: + execution_stats["buy_no_slot"] += len(candidates) + return + + selected = candidates[:slots] + market_value_before = _market_value() + account_equity_before_buy = cash + market_value_before + if account_equity_before_buy <= 0 or max_exposure_pct <= 0: + execution_stats["buy_exposure"] += len(selected) + return + target_position_value = account_equity_before_buy * max_exposure_pct / max_positions + max_exposure_value = account_equity_before_buy * max_exposure_pct + exposure_capacity = max_exposure_value - market_value_before + if exposure_capacity <= 0: + execution_stats["buy_exposure"] += len(selected) + return + + weights = np.repeat(1 / len(selected), len(selected)) + if config.position_sizing == "score_weight": + raw = np.array([max(x[2], 0.0) for x in selected], dtype=float) + if raw.sum() > 0: + weights = raw / raw.sum() + total_budget = min(cash, exposure_capacity, target_position_value * len(selected)) + + for (idx, sym, _score), weight in zip(selected, weights): + if len(positions) >= max_positions: + _count("buy_no_slot") + break + current_market_value = _market_value() + current_equity = cash + current_market_value + current_exposure_capacity = current_equity * max_exposure_pct - current_market_value + allocation = min(total_budget * float(weight), target_position_value, cash, current_exposure_capacity) + if allocation <= 0: + _count("buy_exposure") + continue + entry_price = float(prices[idx]) + shares = np.floor(allocation / (entry_price * (1 + buy_cost_pct)) / 100) * 100 + entry_value = shares * entry_price * (1 + buy_cost_pct) + if shares <= 0: + _count("buy_lot_size") + continue + if entry_value > cash + 1e-6: + _count("buy_cash") + continue + if entry_value > current_exposure_capacity + 1e-6: + _count("buy_exposure") + continue + cash -= entry_value + positions[sym] = { + "symbol": sym, + "name": str(names[idx] or ""), + "entry_date": self._date_str(panel_dates[idx]), + "entry_signal_date": entry_signal_dates[idx] or self._date_str(panel_dates[idx]), + "entry_price": entry_price, + "entry_value": entry_value, + "shares": shares, + "lots": shares / 100, + "position_pct": entry_value / account_equity_before_buy if account_equity_before_buy > 0 else 0.0, + "entry_score": _score, + "max_high": entry_price, + "hold_days": 0, + "pending_exit_reason": None, + "pending_exit_signal_date": None, + "blocked_exit_days": 0, + } + + close_mode = config.matching == "close_t" + for d_idx, d_str in enumerate(all_dates): + if d_idx % 20 == 0: + if cancel_event is not None and cancel_event.is_set(): + logger.info("回测被用户取消 (第 %d/%d 天)", d_idx, len(all_dates)) + break + if progress_cb is not None: + try: + progress_cb({ + "day": d_idx + 1, + "total": len(all_dates), + "date": str(d_str)[:10], + "equity": round(cash + _market_value(), 2), + }) + except Exception: + pass + + idxs = date_to_indices[d_str] + row_by_symbol = {str(panel_symbols[i]): i for i in idxs} + sold_today: set[str] = set() + + for pos in positions.values(): + pos["hold_days"] += 1 + + if close_mode: + _process_risk_exits(d_str, row_by_symbol, sold_today) + _process_scheduled_exits(d_idx, d_str, row_by_symbol, sold_today) + if d_idx < len(all_dates) - 1: + _process_entries(d_str, idxs, sold_today) + else: + _process_scheduled_exits(d_idx, d_str, row_by_symbol, sold_today) + if d_idx < len(all_dates) - 1: + _process_entries(d_str, idxs, sold_today) + _process_risk_exits(d_str, row_by_symbol, sold_today) + + for sym, pos in positions.items(): + idx = row_by_symbol.get(sym) + if idx is not None: + hi = float(high_prices[idx]) + if _valid_price(hi): + pos["max_high"] = max(float(pos.get("max_high", pos["entry_price"])), hi) + + for i in idxs: + c = float(close_prices[i]) + if c > 0 and np.isfinite(c): + last_close[str(panel_symbols[i])] = c + + market_value = _market_value() + equity = cash + market_value + peak = max(peak, equity) + dd = (equity - peak) / peak if peak > 0 else 0.0 + exposure = market_value / equity if equity > 0 else 0.0 + equity_curve.append({ + "date": d_str[:10], + "value": round(float(equity), 2), + "cash": round(float(cash), 2), + "positions": len(positions), + "exposure": round(float(exposure), 4), + }) + drawdown_curve.append({"date": d_str[:10], "value": round(float(dd), 4)}) + + stats = self._calc_portfolio_stats(equity_curve, trades, config.initial_capital) + stats["execution"] = execution_stats + stats["pending_exit_positions"] = sum(1 for p in positions.values() if p.get("pending_exit_reason")) + per_symbol = self._calc_per_symbol(trades) + return SimResult( + equity_curve=equity_curve, + drawdown_curve=drawdown_curve, + trades=trades, + per_symbol_stats=per_symbol, + stats=stats, + ) + + # ── 净值曲线 ────────────────────────────────────── + + @staticmethod + def _build_curves( + trades: list[TradeRecord], + all_dates: np.ndarray, + initial_capital: float, + ) -> tuple[list[dict], list[dict]]: + """从交易记录构建日频净值曲线和回撤曲线。 + + 资金模型: 每笔交易等权分配 (1/N_capital),N_capital = 同时持仓数上限。 + 简化版: 按出场日归集所有已平仓交易的平均收益作为当日组合收益。 + """ + if not trades or len(all_dates) == 0: + return [], [] + + # 按出场日归集 pnl + exit_pnl: dict[str, list[float]] = {} + for t in trades: + d_str = str(t.exit_date) + exit_pnl.setdefault(d_str, []).append(t.pnl_pct) + + equity = initial_capital + peak = initial_capital + curve: list[dict] = [] + dd_curve: list[dict] = [] + + for d in all_dates: + d_str = str(d.item() if hasattr(d, "item") else d) + pnls = exit_pnl.get(d_str, []) + # 当日组合收益 = 该日所有出场交易的平均收益 + daily_ret = float(np.mean(pnls)) if pnls else 0.0 + equity *= (1 + daily_ret) + peak = max(peak, equity) + dd = (equity - peak) / peak if peak > 0 else 0.0 + curve.append({"date": d_str[:10], "value": round(equity, 2)}) + dd_curve.append({"date": d_str[:10], "value": round(dd, 4)}) + + return curve, dd_curve + + # ── 统计计算 ────────────────────────────────────── + + @staticmethod + def _calc_stats( + trades: list[TradeRecord], + initial_capital: float, + start: date, + end: date, + ) -> dict: + if not trades: + return {"total_return": 0, "n_trades": 0} + + pnls = np.array([t.pnl_pct for t in trades]) + n_trades = len(trades) + + # 从净值曲线推算总收益 (等权组合) + cumulative = 1.0 + for p in pnls: + cumulative *= (1 + p) + # 修正: 等权组合的总收益不等于各笔复乘,用曲线终点更准 + # 但这里作为简化,用各笔复乘作为近似 + total_return = cumulative - 1.0 + + # 年化 + n_days = max((end - start).days, 1) + years = n_days / 365.25 + if total_return > -1.0 and years > 0: + annual_return = (1 + total_return) ** (1 / years) - 1 + else: + annual_return = total_return + + # 胜率 + wins = pnls[pnls > 0] + losses = pnls[pnls <= 0] + win_rate = len(wins) / n_trades + + # 盈亏比 + avg_win = float(np.mean(wins)) if len(wins) > 0 else 0.0 + avg_loss = abs(float(np.mean(losses))) if len(losses) > 0 else 0.0 + profit_factor = avg_win / avg_loss if avg_loss > 0 else (float("inf") if avg_win > 0 else 0.0) + + # 最大回撤 — 用交易序列近似 + equity = initial_capital + peak = initial_capital + max_dd = 0.0 + for p in pnls: + equity *= (1 + p) + peak = max(peak, equity) + dd = (equity - peak) / peak + max_dd = min(max_dd, dd) + + # 夏普 — 用交易收益标准差近似 + sharpe = float(np.mean(pnls) / np.std(pnls)) * np.sqrt(252) if np.std(pnls) > 0 else 0.0 + + # Calmar + calmar = annual_return / abs(max_dd) if abs(max_dd) > 0.001 else 0.0 + + return { + "total_return": round(float(total_return), 4), + "annual_return": round(float(annual_return), 4), + "max_drawdown": round(float(max_dd), 4), + "sharpe": round(float(sharpe), 2), + "calmar": round(float(calmar), 2), + "win_rate": round(float(win_rate), 4), + "profit_factor": round(float(profit_factor), 2) if np.isfinite(profit_factor) else None, + "n_trades": n_trades, + "avg_pnl": round(float(np.mean(pnls)), 4), + "avg_win": round(avg_win, 4), + "avg_loss": round(avg_loss, 4), + } + + @staticmethod + def _calc_per_symbol(trades: list[TradeRecord]) -> list[dict]: + if not trades: + return [] + by_sym: dict[str, dict] = {} + for t in trades: + s = t.symbol + d = by_sym.setdefault(s, { + "symbol": s, "n_trades": 0, "total_return": 1.0, + "best": -999.0, "worst": 999.0, "wins": 0, "pnls": [], + }) + d["n_trades"] += 1 + d["pnls"].append(t.pnl_pct) + d["total_return"] *= (1 + t.pnl_pct) + d["best"] = max(d["best"], t.pnl_pct) + d["worst"] = min(d["worst"], t.pnl_pct) + if t.pnl_pct > 0: + d["wins"] += 1 + + result = [] + for d in by_sym.values(): + result.append({ + "symbol": d["symbol"], + "n_trades": d["n_trades"], + "total_return": round(d["total_return"] - 1.0, 4), + "win_rate": round(d["wins"] / d["n_trades"], 4) if d["n_trades"] > 0 else 0.0, + "best": round(d["best"], 4), + "worst": round(d["worst"], 4), + }) + return sorted(result, key=lambda x: x["total_return"], reverse=True) + + @staticmethod + def _calc_independent_candidate_result( + trades: list[TradeRecord], + n_candidates: int, + execution_stats: dict[str, int], + ) -> SimResult: + """全量独立候选统计:按每个候选样本的实际执行收益聚合。""" + if not trades: + return SimResult( + equity_curve=[], + drawdown_curve=[], + trades=[], + per_symbol_stats=[], + stats={ + "mode": "full", + "full_kind": "candidate_execution", + "error": "no executable trades", + "n_candidates": int(n_candidates), + "n_trades": 0, + "execution": execution_stats, + }, + ) + + pnls = np.array([t.pnl_pct for t in trades], dtype=float) + durations = np.array([t.duration for t in trades], dtype=float) + wins = pnls[pnls > 0] + losses = pnls[pnls <= 0] + avg_win = float(np.mean(wins)) if len(wins) else 0.0 + avg_loss = abs(float(np.mean(losses))) if len(losses) else 0.0 + + # 按退出日聚合已实现样本收益, 构造“样本收益曲线”。它不是账户净值。 + daily_returns: dict[str, list[float]] = {} + for t in trades: + daily_returns.setdefault(str(t.exit_date)[:10], []).append(float(t.pnl_pct)) + + equity_curve: list[dict] = [] + drawdown_curve: list[dict] = [] + equity = 1.0 + peak = 1.0 + daily_avg: list[float] = [] + for d_str in sorted(daily_returns.keys()): + values = daily_returns[d_str] + avg_ret = float(np.mean(values)) if values else 0.0 + daily_avg.append(avg_ret) + equity *= (1 + avg_ret) + peak = max(peak, equity) + dd = (equity - peak) / peak if peak > 0 else 0.0 + equity_curve.append({ + "date": d_str, + "value": round(float(equity), 4), + "positions": len(values), + }) + drawdown_curve.append({"date": d_str, "value": round(float(dd), 4)}) + + values = np.array([r["value"] for r in equity_curve], dtype=float) + total_return = float(values[-1] - 1.0) if len(values) else 0.0 + peaks = np.maximum.accumulate(values) if len(values) else np.array([]) + drawdowns = values / peaks - 1 if len(values) else np.array([]) + max_drawdown = float(drawdowns.min()) if len(drawdowns) else 0.0 + daily = np.array(daily_avg, dtype=float) + sharpe = float(np.mean(daily) / np.std(daily) * np.sqrt(252)) if len(daily) > 1 and np.std(daily) > 0 else 0.0 + + lo, hi, nbins = -0.20, 0.20, 20 + clipped = np.clip(pnls, lo, hi) + counts, edges = np.histogram(clipped, bins=nbins, range=(lo, hi)) + dist = [ + { + "range": f"{(edges[i]*100):+.0f}~{(edges[i+1]*100):+.0f}%", + "count": int(counts[i]), + "ratio": round(float(counts[i] / pnls.size), 4) if pnls.size else 0.0, + } + for i in range(nbins) + ] + + stats = { + "mode": "full", + "full_kind": "candidate_execution", + "n_candidates": int(n_candidates), + "n_trades": int(len(trades)), + "n_days": int(len(daily_returns)), + "avg_daily_candidates": round(float(len(trades) / max(len(daily_returns), 1)), 1), + "avg_return": round(float(np.mean(pnls)), 4), + "median_return": round(float(np.median(pnls)), 4), + "win_rate": round(float(len(wins) / len(pnls)), 4) if len(pnls) else 0.0, + "profit_factor": round(float(avg_win / avg_loss), 2) if avg_loss > 0 else None, + "best": round(float(np.max(pnls)), 4), + "worst": round(float(np.min(pnls)), 4), + "avg_duration": round(float(np.mean(durations)), 1) if len(durations) else 0.0, + "total_return": round(float(total_return), 4), + "max_drawdown": round(float(max_drawdown), 4), + "sharpe": round(float(sharpe), 2), + "return_distribution": dist, + "execution": execution_stats, + } + + return SimResult( + equity_curve=equity_curve, + drawdown_curve=drawdown_curve, + trades=trades, + per_symbol_stats=BacktestEngine._calc_per_symbol(trades), + stats=stats, + ) + + @staticmethod + def _calc_portfolio_stats( + equity_curve: list[dict], + trades: list[TradeRecord], + initial_capital: float, + ) -> dict: + if not equity_curve: + return {"total_return": 0, "n_trades": 0} + final_equity = float(equity_curve[-1]["value"]) + total_return = final_equity / initial_capital - 1 if initial_capital > 0 else 0.0 + values = np.array([float(r["value"]) for r in equity_curve], dtype=float) + daily = values[1:] / values[:-1] - 1 if len(values) > 1 else np.array([]) + annual_return = (1 + total_return) ** (252 / max(len(equity_curve), 1)) - 1 if total_return > -1 else total_return + peaks = np.maximum.accumulate(values) + drawdowns = values / peaks - 1 + max_drawdown = float(drawdowns.min()) if len(drawdowns) else 0.0 + sharpe = float(np.mean(daily) / np.std(daily) * np.sqrt(252)) if len(daily) and np.std(daily) > 0 else 0.0 + pnls = np.array([t.pnl_pct for t in trades], dtype=float) if trades else np.array([]) + exposures = np.array([float(r.get("exposure", 0.0)) for r in equity_curve], dtype=float) + wins = pnls[pnls > 0] + losses = pnls[pnls <= 0] + avg_win = float(np.mean(wins)) if len(wins) else 0.0 + avg_loss = abs(float(np.mean(losses))) if len(losses) else 0.0 + return { + "total_return": round(float(total_return), 4), + "annual_return": round(float(annual_return), 4), + "max_drawdown": round(float(max_drawdown), 4), + "sharpe": round(float(sharpe), 2), + "calmar": round(float(annual_return / abs(max_drawdown)), 2) if abs(max_drawdown) > 0.001 else 0.0, + "win_rate": round(float(len(wins) / len(pnls)), 4) if len(pnls) else 0.0, + "profit_factor": round(float(avg_win / avg_loss), 2) if avg_loss > 0 else None, + "n_trades": len(trades), + "avg_pnl": round(float(np.mean(pnls)), 4) if len(pnls) else 0.0, + "avg_win": round(avg_win, 4), + "avg_loss": round(avg_loss, 4), + "final_equity": round(final_equity, 2), + "initial_capital": round(float(initial_capital), 2), + "avg_exposure": round(float(np.mean(exposures)), 4) if len(exposures) else 0.0, + "max_exposure": round(float(np.max(exposures)), 4) if len(exposures) else 0.0, + } + + @staticmethod + def _date_str(value) -> str: + value = value.item() if hasattr(value, "item") else value + return str(value)[:10] + + @staticmethod + def _empty_result() -> SimResult: + return SimResult( + equity_curve=[], drawdown_curve=[], trades=[], + per_symbol_stats=[], stats={"error": "no data or no signals"}, + ) + + # ── 截面工具 (因子回测用) ───────────────────────── + + @staticmethod + def cross_section_rank(panel: pl.DataFrame, col: str) -> pl.DataFrame: + return panel.with_columns( + pl.col(col).rank(method="random").over("date").alias(f"{col}_rank") + ) + + @staticmethod + def cross_section_qcut(panel: pl.DataFrame, col: str, n_groups: int) -> pl.DataFrame: + return panel.with_columns( + pl.col(col).qcut(n_groups, labels=[f"Q{i+1}" for i in range(n_groups)]) + .over("date").alias("_group") + ) diff --git a/backend/app/backtest/factor.py b/backend/app/backtest/factor.py new file mode 100644 index 0000000..740582a --- /dev/null +++ b/backend/app/backtest/factor.py @@ -0,0 +1,480 @@ +"""因子回测服务 — IC/IR 分析 + 分层回测 + 多空组合。 + +纯 Polars 向量化实现,无 pandas 依赖。 +""" +from __future__ import annotations + +import logging +import time +import uuid +from dataclasses import dataclass, field +from datetime import date, timedelta +from typing import Literal + +import numpy as np +import polars as pl + +from app.backtest.engine import BacktestEngine + +logger = logging.getLogger(__name__) + +# 可用因子列 (从 ENRICHED_COLUMNS 过滤出数值型指标) +FACTOR_COLUMNS: list[dict] = [ + {"id": "momentum_5d", "label": "5日动量", "group": "动量", "desc": "5日涨跌幅,正值表示上涨趋势"}, + {"id": "momentum_10d", "label": "10日动量", "group": "动量", "desc": "10日涨跌幅,中短期趋势指标"}, + {"id": "momentum_20d", "label": "20日动量", "group": "动量", "desc": "月度涨跌幅,常用因子"}, + {"id": "momentum_30d", "label": "30日动量", "group": "动量", "desc": "30日涨跌幅"}, + {"id": "momentum_60d", "label": "60日动量", "group": "动量", "desc": "季度涨跌幅,中期动量"}, + {"id": "rsi_6", "label": "RSI(6)", "group": "超买超卖", "desc": "6日相对强弱指标,敏感度高"}, + {"id": "rsi_14", "label": "RSI(14)", "group": "超买超卖", "desc": "14日相对强弱指标,经典周期"}, + {"id": "rsi_24", "label": "RSI(24)", "group": "超买超卖", "desc": "24日相对强弱指标"}, + {"id": "annual_vol_20d","label": "20日波动率", "group": "波动率", "desc": "20日年化波动率"}, + {"id": "atr_14", "label": "ATR(14)", "group": "波动率", "desc": "14日平均真实波幅"}, + {"id": "vol_ratio_5d", "label": "量比(5日)", "group": "量价", "desc": "当日成交量 / 5日均量"}, + {"id": "turnover_rate", "label": "换手率", "group": "量价", "desc": "当日换手率"}, + {"id": "macd_hist", "label": "MACD柱", "group": "趋势", "desc": "MACD柱状图值"}, + {"id": "kdj_k", "label": "KDJ-K", "group": "趋势", "desc": "KDJ指标K值"}, + {"id": "change_pct", "label": "日涨跌幅", "group": "基础", "desc": "当日涨跌幅"}, + {"id": "amplitude", "label": "日振幅", "group": "基础", "desc": "当日振幅 (最高-最低)/昨收"}, +] + +FACTOR_WARMUP_DAYS = 120 + + +@dataclass +class FactorConfig: + factor_name: str + symbols: list[str] | None + start: date + end: date + n_groups: int = 5 + rebalance: Literal["daily", "weekly", "monthly"] = "monthly" + weight: Literal["equal", "factor_weight"] = "equal" + fees_pct: float = 0.0002 + slippage_bps: float = 5.0 + + +@dataclass +class GroupStats: + group: int + label: str + total_return: float + annual_return: float + max_drawdown: float + sharpe: float + win_rate: float + + +@dataclass +class FactorResult: + run_id: str + config: dict + # IC 分析 + ic_mean: float | None = None + ic_std: float | None = None + ir: float | None = None + ic_win_rate: float | None = None + ic_series: list[dict] = field(default_factory=list) + # 分层 + group_stats: list[dict] = field(default_factory=list) + group_nav: list[dict] = field(default_factory=list) + # 多空 + long_short_stats: dict = field(default_factory=dict) + long_short_nav: list[dict] = field(default_factory=list) + # 元信息 + elapsed_ms: float = 0.0 + n_symbols: int = 0 + n_dates: int = 0 + error: str | None = None + + +class FactorBacktestService: + def __init__(self, engine: BacktestEngine) -> None: + self.engine = engine + + def run(self, config: FactorConfig) -> FactorResult: + t0 = time.perf_counter() + run_id = uuid.uuid4().hex[:10] + + def _err(msg: str) -> FactorResult: + return FactorResult( + run_id=run_id, + config=self._config_to_dict(config), + error=msg, + elapsed_ms=(time.perf_counter() - t0) * 1000, + ) + + # 加载基础面板: 当前 enriched parquet 只持久化基础列, 指标因子可能需要运行时计算。 + panel_columns = ["symbol", "date", "open", "high", "low", "close", "volume", "turnover_rate"] + if config.factor_name not in panel_columns: + panel_columns.append(config.factor_name) + load_start = config.start + if config.factor_name not in {"turnover_rate"}: + load_start = config.start - timedelta(days=FACTOR_WARMUP_DAYS) + + panel = self.engine.load_panel( + config.symbols, + load_start, + config.end, + columns=panel_columns, + ) + if panel.is_empty(): + return _err("无数据,请检查日期范围或先运行盘后管道") + + factor_col = config.factor_name + if factor_col not in panel.columns: + panel = self._compute_missing_factor(panel, factor_col) + if factor_col not in panel.columns: + return _err(f"因子列 '{factor_col}' 不存在于 enriched 数据中, 且无法从基础行情计算") + if "close" not in panel.columns: + return _err("enriched 数据缺少收盘价 close") + panel = panel.select(["symbol", "date", "close", factor_col]) + panel = panel.filter((pl.col("date") >= config.start) & (pl.col("date") <= config.end)) + + # 过滤有效行 + panel = panel.filter( + pl.col(factor_col).is_not_null() + & pl.col("close").is_not_null() + & (pl.col("close") > 0) + ) + if panel.is_empty(): + return _err("过滤后无有效数据") + + n_symbols = panel["symbol"].n_unique() + n_dates = panel["date"].n_unique() + + # 计算下期收益 + # 根据调仓频率计算不同周期的 forward return + if config.rebalance == "daily": + panel = panel.with_columns( + (pl.col("close").shift(-1).over("symbol") / pl.col("close") - 1) + .alias("_next_return") + ) + else: + # weekly/monthly: 计算到下个调仓日的收益 + panel = self._calc_period_return(panel, config.rebalance) + + # ── 1. IC 分析 ── + ic_df = self._calc_ic(panel, factor_col) + ic_series = [ + {"date": str(row["date"]), "ic": round(float(row["ic"]), 4)} + for row in ic_df.iter_rows(named=True) + if row["ic"] is not None and not np.isnan(float(row["ic"])) + ] + ic_values = [r["ic"] for r in ic_series] + ic_mean = float(np.mean(ic_values)) if ic_values else None + ic_std = float(np.std(ic_values)) if ic_values else None + ir = (ic_mean / ic_std) if (ic_mean is not None and ic_std and ic_std > 1e-8) else None + ic_win_rate = (sum(1 for v in ic_values if v > 0) / len(ic_values)) if ic_values else None + + # ── 2. 分层回测 ── + panel = self._add_groups(panel, factor_col, config.n_groups) + group_nav = self._calc_group_nav(panel, config) + group_stats = self._calc_group_stats(group_nav, config.start, config.end) + + # ── 3. 多空组合 ── + long_short_nav, long_short_stats = self._calc_long_short(group_nav, config) + + elapsed = (time.perf_counter() - t0) * 1000 + return FactorResult( + run_id=run_id, + config=self._config_to_dict(config), + ic_mean=round(ic_mean, 4) if ic_mean is not None else None, + ic_std=round(ic_std, 4) if ic_std is not None else None, + ir=round(ir, 4) if ir is not None else None, + ic_win_rate=round(ic_win_rate, 4) if ic_win_rate is not None else None, + ic_series=ic_series, + group_stats=group_stats, + group_nav=group_nav, + long_short_stats=long_short_stats, + long_short_nav=long_short_nav, + elapsed_ms=round(elapsed, 1), + n_symbols=n_symbols, + n_dates=n_dates, + ) + + @staticmethod + def _compute_missing_factor(panel: pl.DataFrame, factor_col: str) -> pl.DataFrame: + required = {"symbol", "date", "open", "high", "low", "close", "volume"} + if not required.issubset(panel.columns): + missing = sorted(required - set(panel.columns)) + logger.warning("factor %s cannot be computed, missing columns: %s", factor_col, missing) + return panel + + from app.indicators.pipeline import compute_indicators + + computed = compute_indicators(panel) + if factor_col not in computed.columns: + return panel + return computed.select(["symbol", "date", "close", factor_col]) + + # ── IC 计算 ── + + @staticmethod + def _calc_ic(panel: pl.DataFrame, factor_col: str) -> pl.DataFrame: + """计算截面 Rank IC (因子值 rank vs 下期收益 rank 的相关系数)。""" + return ( + panel.filter(pl.col("_next_return").is_not_null()) + .group_by("date") + .agg( + pl.corr( + pl.col(factor_col).rank(method="random"), + pl.col("_next_return").rank(method="random"), + ).alias("ic") + ) + .sort("date") + ) + + # ── 调仓期收益 ── + + @staticmethod + def _calc_period_return(panel: pl.DataFrame, rebalance: str) -> pl.DataFrame: + """计算到下个调仓日的收益。 + + weekly: 下周一的 open / 今日 close - 1 + monthly: 下月首个交易日的 open / 今日 close - 1 + 只在调仓日标记行有效,其他行为 null。 + """ + import datetime as _dt + + all_dates = sorted(panel["date"].unique().to_list()) + date_set = set(all_dates) + + if rebalance == "weekly": + # 调仓日 = 每周一 + rebalance_dates = set() + for d in all_dates: + if hasattr(d, "weekday"): + wd = d.weekday() + else: + wd = _dt.date.fromisoformat(str(d)).weekday() + if wd == 0: # Monday + rebalance_dates.add(d) + else: # monthly + # 调仓日 = 每月首个交易日 + seen_months: set[str] = set() + rebalance_dates = set() + for d in sorted(all_dates): + m = str(d)[:7] # "YYYY-MM" + if m not in seen_months: + seen_months.add(m) + rebalance_dates.add(d) + + if not rebalance_dates: + panel = panel.with_columns(pl.lit(None).cast(pl.Float64).alias("_next_return")) + return panel + + # 对每个调仓日,找到下一个调仓日 + sorted_rebalance = sorted(rebalance_dates) + next_rebalance_map: dict = {} + for i, d in enumerate(sorted_rebalance): + if i + 1 < len(sorted_rebalance): + next_rebalance_map[d] = sorted_rebalance[i + 1] + # 最后一个调仓日没有下一个,不计算收益 + + # 构建 (date, symbol) → next_rebalance_date 的 close 价格映射 + # 简化: 用下个调仓日的 close / 当前 close + panel = panel.sort(["symbol", "date"]) + dates_col = panel["date"].to_list() + close_col = panel["close"].to_list() + symbol_col = panel["symbol"].to_list() + + # 先找下个调仓日的 close + # 建立 (date, symbol) → close 的快速查找 + price_map: dict[tuple, float] = {} + for i in range(len(dates_col)): + price_map[(str(dates_col[i]), symbol_col[i])] = close_col[i] + + next_returns = [None] * len(panel) + for i in range(len(panel)): + d = dates_col[i] + d_val = d if isinstance(d, _dt.date) else _dt.date.fromisoformat(str(d)) + if d not in rebalance_dates: + continue + next_d = next_rebalance_map.get(d) + if next_d is None: + continue + next_d_str = str(next_d)[:10] + d_str = str(d)[:10] + sym = symbol_col[i] + next_close = price_map.get((next_d_str, sym)) + cur_close = close_col[i] + if next_close is not None and cur_close and cur_close > 0: + next_returns[i] = (next_close / cur_close - 1.0) + + panel = panel.with_columns( + pl.Series("_next_return", next_returns, dtype=pl.Float64) + ) + return panel + + # ── 分组 ── + + @staticmethod + def _add_groups(panel: pl.DataFrame, factor_col: str, n_groups: int) -> pl.DataFrame: + """截面分位数分组。""" + return panel.with_columns( + pl.col(factor_col) + .qcut(n_groups, labels=[f"Q{i+1}" for i in range(n_groups)]) + .over("date") + .alias("_group") + ) + + # ── 分组净值 ── + + @staticmethod + def _calc_group_nav(panel: pl.DataFrame, config: FactorConfig) -> list[dict]: + """计算分组净值曲线 — 只在调仓日更新净值。""" + # 只保留有下期收益的行 (= 调仓日) + group_ret = ( + panel.filter(pl.col("_next_return").is_not_null() & pl.col("_group").is_not_null()) + .group_by(["date", "_group"]) + .agg(pl.col("_next_return").mean().alias("group_return")) + ) + + # pivot: date × group + pivot = group_ret.pivot(index="date", columns="_group", values="group_return").sort("date") + + if pivot.is_empty(): + return [] + + group_cols = [c for c in pivot.columns if c != "date"] + + # 累乘净值曲线 + result: list[dict] = [] + nav_values: dict[str, float] = {c: 1.0 for c in group_cols} + + for row in pivot.iter_rows(named=True): + entry: dict = {"date": str(row["date"])[:10]} + for c in group_cols: + ret = float(row[c]) if row[c] is not None else 0.0 + nav_values[c] *= (1 + ret) + entry[c] = round(nav_values[c], 4) + result.append(entry) + + return result + + # ── 分组统计 ── + + @staticmethod + def _calc_group_stats( + group_nav: list[dict], start: date, end: date, + ) -> list[dict]: + if not group_nav: + return [] + + group_cols = [k for k in group_nav[0] if k != "date"] + n_days = max((end - start).days, 1) + years = n_days / 365.25 + + stats = [] + for i, c in enumerate(sorted(group_cols)): + values = [r[c] for r in group_nav if r.get(c) is not None] + if not values: + continue + total_return = values[-1] - 1.0 + annual_return = (values[-1]) ** (1 / max(years, 0.01)) - 1 if values[-1] > 0 else 0.0 + + # 最大回撤 + peak = 1.0 + max_dd = 0.0 + for v in values: + peak = max(peak, v) + dd = (v - peak) / peak + max_dd = min(max_dd, dd) + + # 日收益序列 + daily_rets = [] + for j in range(1, len(values)): + if values[j - 1] > 0: + daily_rets.append(values[j] / values[j - 1] - 1) + + # 夏普 + if daily_rets: + arr = np.array(daily_rets) + sharpe = float(np.mean(arr) / np.std(arr)) * np.sqrt(252) if np.std(arr) > 0 else 0.0 + win_rate = float(np.mean(arr > 0)) + else: + sharpe = 0.0 + win_rate = 0.0 + + stats.append({ + "group": i + 1, + "label": c, + "total_return": round(total_return, 4), + "annual_return": round(annual_return, 4), + "max_drawdown": round(max_dd, 4), + "sharpe": round(sharpe, 2), + "win_rate": round(win_rate, 4), + }) + + return stats + + # ── 多空组合 ── + + @staticmethod + def _calc_long_short( + group_nav: list[dict], config: FactorConfig, + ) -> tuple[list[dict], dict]: + """多空组合: 做多最高组 + 做空最低组。""" + if not group_nav: + return [], {} + + group_cols = sorted([k for k in group_nav[0] if k != "date"]) + if len(group_cols) < 2: + return [], {} + + top_col = group_cols[-1] # Q5 (最高) + bottom_col = group_cols[0] # Q1 (最低) + + # 独立计算 top 和 bottom 的日收益,然后合成 + ls_value = 1.0 + prev_top = 1.0 + prev_bot = 1.0 + peak = 1.0 + max_dd = 0.0 + ls_nav: list[dict] = [] + + for row in group_nav: + top_nav = float(row.get(top_col, 1.0)) if row.get(top_col) is not None else 1.0 + bot_nav = float(row.get(bottom_col, 1.0)) if row.get(bottom_col) is not None else 1.0 + + # top 组收益 (做多) + top_ret = (top_nav / prev_top - 1) if prev_top > 0 else 0.0 + # bottom 组收益 (做空 = 取反) + bot_ret = -(bot_nav / prev_bot - 1) if prev_bot > 0 else 0.0 + # 多空组合收益 + ls_ret = (top_ret + bot_ret) / 2 # 各分配 50% 资金 + ls_value *= (1 + ls_ret) + + prev_top = top_nav + prev_bot = bot_nav + + peak = max(peak, ls_value) + dd = (ls_value - peak) / peak if peak > 0 else 0.0 + max_dd = min(max_dd, dd) + + ls_nav.append({"date": row["date"], "value": round(ls_value, 4)}) + + total_ret = ls_value - 1.0 + ls_stats = { + "total_return": round(total_ret, 4), + "max_drawdown": round(max_dd, 4), + "top_group": top_col, + "bottom_group": bottom_col, + } + + return ls_nav, ls_stats + + @staticmethod + def _config_to_dict(c: FactorConfig) -> dict: + return { + "factor_name": c.factor_name, + "symbols": c.symbols, + "start": str(c.start), + "end": str(c.end), + "n_groups": c.n_groups, + "rebalance": c.rebalance, + "weight": c.weight, + "fees_pct": c.fees_pct, + "slippage_bps": c.slippage_bps, + } diff --git a/backend/app/backtest/strategy.py b/backend/app/backtest/strategy.py new file mode 100644 index 0000000..e6f597f --- /dev/null +++ b/backend/app/backtest/strategy.py @@ -0,0 +1,701 @@ +"""策略回测服务 — 复用 StrategyDef 体系做全周期回测。 + +核心优化: 向量化 filter_fn,不逐日调用 StrategyEngine.run()。 +""" +from __future__ import annotations + +import logging +import time +import uuid +from dataclasses import dataclass, field +from datetime import date, timedelta +from typing import Callable, Literal + +import numpy as np +import polars as pl + +from app.backtest.engine import BacktestEngine, MatcherConfig, SimResult +from app.strategy.engine import StrategyEngine, StrategyDef + +logger = logging.getLogger(__name__) + +BENCHMARK_SYMBOL = "000001.SH" + + +@dataclass +class StrategyBacktestConfig: + strategy_id: str + symbols: list[str] | None + start: date + end: date + params: dict | None = None + overrides: dict | None = None + matching: Literal["close_t", "open_t+1"] = "open_t+1" + fees_pct: float = 0.0002 + slippage_bps: float = 5.0 + max_positions: int = 10 + max_exposure_pct: float = 1.0 + initial_capital: float = 1_000_000.0 + position_sizing: Literal["equal", "score_weight"] = "equal" + mode: Literal["position", "full"] = "position" + holding_days: int = 5 + + +@dataclass +class StrategyBacktestResult: + run_id: str + config: dict + stats: dict = field(default_factory=dict) + equity_curve: list[dict] = field(default_factory=list) + drawdown_curve: list[dict] = field(default_factory=list) + benchmark_curve: list[dict] = field(default_factory=list) + trades: list[dict] = field(default_factory=list) + per_symbol_stats: list[dict] = field(default_factory=list) + strategy_info: dict = field(default_factory=dict) + elapsed_ms: float = 0.0 + error: str | None = None + + +class StrategyBacktestService: + def __init__( + self, + engine: BacktestEngine, + strategy_engine: StrategyEngine, + ) -> None: + self.engine = engine + self.strategy_engine = strategy_engine + + def run( + self, + config: StrategyBacktestConfig, + progress_cb: "Callable[[dict], None] | None" = None, + cancel_event: "threading.Event | None" = None, + ) -> StrategyBacktestResult: + t0 = time.perf_counter() + run_id = uuid.uuid4().hex[:10] + + def _err(msg: str) -> StrategyBacktestResult: + return StrategyBacktestResult( + run_id=run_id, + config=self._config_to_dict(config), + error=msg, + elapsed_ms=(time.perf_counter() - t0) * 1000, + ) + + # 获取策略定义 + try: + s = self.strategy_engine.get(config.strategy_id) + except ValueError as e: + return _err(str(e)) + + params = self._normalize_params(config.params or {}, s) + overrides = config.overrides or {} + basic_filter = self._effective_basic_filter(s, overrides) + entry_signals = self._effective_signals(overrides, "entry_signals", s.entry_signals) + exit_signals = self._effective_signals(overrides, "exit_signals", s.exit_signals) + stop_loss = self._override_value(overrides, "stop_loss", s.stop_loss) + trailing_stop = self._normalize_pct( + self._override_value(overrides, "trailing_stop", getattr(s, "trailing_stop", None)), + 0.005, + 0.5, + ) + trailing_take_profit_activate = self._normalize_pct( + self._override_value(overrides, "trailing_take_profit_activate", getattr(s, "trailing_take_profit_activate", None)), + 0.01, + 2.0, + ) + trailing_take_profit_drawdown = self._normalize_pct( + self._override_value(overrides, "trailing_take_profit_drawdown", getattr(s, "trailing_take_profit_drawdown", None)), + 0.005, + 0.5, + ) + if trailing_take_profit_activate is not None and trailing_take_profit_drawdown is not None: + trailing_take_profit_drawdown = min(trailing_take_profit_drawdown, trailing_take_profit_activate) + max_hold_days = self._override_value(overrides, "max_hold_days", s.max_hold_days) + score_min, score_max = self._normalize_score_range( + overrides.get("score_min"), + overrides.get("score_max"), + ) + + timing_ms: dict[str, float] = {} + + # 加载面板 (含 warmup + 全量指标 + 信号)。warmup 只用于指标/形态计算, 不参与正式交易。 + warmup_days = max(120, int(max(s.lookback_days or 1, 1) * 1.5)) + load_start = config.start - timedelta(days=warmup_days) + + # 全量模式: entries 只在正式区间触发, exits 需要 end 之后的尾部数据继续执行策略卖点。 + # 若策略有 max_hold_days, 用它决定尾部窗口;否则 holding_days 只作为兜底观察上限。 + full_horizon_days = int(max_hold_days or config.holding_days or 5) + full_horizon_days = max(full_horizon_days, 1) + load_end = config.end + if config.mode == "full": + fwd_buffer = full_horizon_days + 5 # 多取几天, 容错停牌缺口/open_t+1 + load_end = config.end + timedelta(days=fwd_buffer * 2) # 日历日放宽, 确保覆盖 N 个交易日 + + t_load = time.perf_counter() + panel = self.engine.load_panel(config.symbols, load_start, load_end) + timing_ms["load_panel"] = round((time.perf_counter() - t_load) * 1000, 1) + if panel.is_empty(): + return _err("无数据,请检查日期范围或先运行盘后管道") + + formal_range = self._date_range_mask(panel, config.start, config.end) + if not formal_range.any(): + return _err("正式回测区间内无数据") + + t_signal = time.perf_counter() + + # basic_filter 只影响买入候选, 不能删除行情 panel, 否则持仓 mark / 卖出 / full forward return 都会失真。 + basic_mask = pl.Series("_basic", [True] * len(panel), dtype=pl.Boolean) + if basic_filter and basic_filter.get("enabled", True): + expr = StrategyEngine._basic_filter_expr(panel, basic_filter) + if expr is not None: + try: + basic_mask = panel.select(expr.alias("_basic"))["_basic"].fill_null(False).cast(pl.Boolean) + except Exception as e: # noqa: BLE001 + logger.warning("basic_filter mask failed: %s", e) + return _err(f"基础过滤计算失败: {e}") + + # 策略候选层用于评分归一化;entry_signals 只是买点层, 不参与 score universe。 + candidate_filter_mask = self._build_candidate_filter_mask(panel, s, params) + candidate_mask = basic_mask & candidate_filter_mask + panel = self._apply_score(panel, s, overrides, universe_mask=candidate_mask) + + entry_mask = self._build_entry_mask_from_candidate(panel, candidate_mask, s, entry_signals) + entry_mask = entry_mask & formal_range + raw_exit_mask = self._build_signal_mask(panel, exit_signals, "_exit") + exit_mask = raw_exit_mask & (self._date_range_mask(panel, config.start, load_end) if config.mode == "full" else formal_range) + timing_ms["signals_score"] = round((time.perf_counter() - t_signal) * 1000, 1) + + if not entry_mask.any(): + return _err("在指定区间内未产生买入信号") + + # warmup 之后才交给撮合;full mode 保留 end 之后前瞻段用于 shift(-N)。 + sim_end = load_end if config.mode == "full" else config.end + sim_range = self._date_range_mask(panel, config.start, sim_end) + sim_panel = panel.filter(sim_range) + sim_entry_mask = entry_mask.filter(sim_range) + sim_exit_mask = exit_mask.filter(sim_range) + if sim_panel.is_empty(): + return _err("正式回测区间内无数据") + + t_sim = time.perf_counter() + matcher_config = MatcherConfig( + matching=config.matching, + fees_pct=config.fees_pct, + slippage_bps=config.slippage_bps, + stop_loss_pct=stop_loss, + trailing_stop_pct=trailing_stop, + trailing_take_profit_activate_pct=trailing_take_profit_activate, + trailing_take_profit_drawdown_pct=trailing_take_profit_drawdown, + max_hold_days=max_hold_days, + max_positions=config.max_positions, + max_exposure_pct=config.max_exposure_pct, + score_min=score_min, + score_max=score_max, + initial_capital=config.initial_capital, + position_sizing=config.position_sizing, + ) + # 撮合 — full 为全候选独立执行;position 为账户级仓位模拟。 + if config.mode == "full": + result = self.engine.simulate_independent_candidates( + sim_panel, + sim_entry_mask, + sim_exit_mask, + matcher_config, + progress_cb, + cancel_event, + ) + else: + result = self.engine.simulate_portfolio(sim_panel, sim_entry_mask, sim_exit_mask, matcher_config, progress_cb, cancel_event) + timing_ms["simulate"] = round((time.perf_counter() - t_sim) * 1000, 1) + + # 检查是否被取消 + if cancel_event is not None and cancel_event.is_set(): + return StrategyBacktestResult( + run_id=run_id, + config=self._config_to_dict(config), + error="cancelled", + elapsed_ms=round((time.perf_counter() - t0) * 1000, 1), + ) + + if result.stats.get("error"): + return _err(result.stats["error"]) + + timing_ms["total"] = round((time.perf_counter() - t0) * 1000, 1) + result.stats["timing_ms"] = timing_ms + result.stats["panel_rows"] = int(sim_panel.height) + + benchmark_curve = self._build_benchmark_curve(config.start, config.end) + + # 构建策略信息 + strategy_info = { + "id": s.meta.get("id", config.strategy_id), + "name": s.meta.get("name", config.strategy_id), + "description": s.meta.get("description", ""), + "entry_signals": entry_signals, + "exit_signals": exit_signals, + "stop_loss": stop_loss, + "trailing_stop": trailing_stop, + "trailing_take_profit_activate": trailing_take_profit_activate, + "trailing_take_profit_drawdown": trailing_take_profit_drawdown, + "max_hold_days": max_hold_days, + "full_horizon_days": full_horizon_days, + "score_min": score_min, + "score_max": score_max, + "source": s.source, + } + + elapsed = (time.perf_counter() - t0) * 1000 + + return StrategyBacktestResult( + run_id=run_id, + config=self._config_to_dict(config), + stats=result.stats, + equity_curve=result.equity_curve, + drawdown_curve=result.drawdown_curve, + benchmark_curve=benchmark_curve, + trades=[self._trade_to_dict(t) for t in result.trades], + per_symbol_stats=result.per_symbol_stats, + strategy_info=strategy_info, + elapsed_ms=round(elapsed, 1), + ) + + # ── 全量模拟 (选股能力统计, 不建组合不算净值) ── + + def _run_full_simulation( + self, + panel: pl.DataFrame, + entry_mask: pl.Series, + holding_days: int, + ) -> SimResult: + """对 entry_mask 命中的全部候选, 算持有 N 天后的前瞻收益统计。 + + 不受 max_positions/资金约束, 反映策略选股能力本身。 + equity_curve 复用为"累计日均超额收益曲线"(基准归零)。 + """ + n = holding_days if holding_days and holding_days > 0 else 5 + + df = panel.with_columns([ + entry_mask.cast(pl.Boolean).alias("_is_candidate"), + (pl.col("close").shift(-n).over("symbol") / pl.col("close") - 1).alias("_fwd_return"), + ]).filter( + pl.col("_is_candidate") + & pl.col("_fwd_return").is_not_null() + & pl.col("_fwd_return").is_not_nan() + ) + + if df.is_empty(): + return self.engine._empty_result() + + fwd = df["_fwd_return"].to_numpy() + wins = fwd[fwd > 0] + losses = fwd[fwd <= 0] + avg_win = float(wins.mean()) if wins.size else 0.0 + avg_loss = abs(float(losses.mean())) if losses.size else 0.0 + + # 按日聚合: 当日候选的平均前瞻收益 + daily = ( + df.group_by("date").agg( + pl.col("_fwd_return").mean().alias("avg_ret"), + pl.col("_fwd_return").count().alias("n_cand"), + ).sort("date") + ) + + # 累计超额曲线: 每日复利平均收益 (基准归零, 故 equity 即累计策略收益) + equity_curve: list[dict] = [] + equity = 1.0 + peak = 1.0 + drawdown_curve: list[dict] = [] + for row in daily.iter_rows(named=True): + ret = float(row["avg_ret"] or 0.0) + equity *= (1 + ret) + peak = max(peak, equity) + dd = (equity - peak) / peak if peak > 0 else 0.0 + d_str = str(row["date"])[:10] + equity_curve.append({ + "date": d_str, + "value": round(equity, 4), + "positions": int(row["n_cand"]), + }) + drawdown_curve.append({"date": d_str, "value": round(dd, 4)}) + + # 同期上证收益 (用 benchmark close 算) + benchmark_curve = self._build_benchmark_curve( + daily["date"].min(), daily["date"].max() + ) + benchmark_return = 0.0 + if benchmark_curve: + closes = [b["close"] for b in benchmark_curve if b.get("close")] + if len(closes) >= 2 and closes[0] > 0: + benchmark_return = closes[-1] / closes[0] - 1 + + total_return = equity - 1.0 + max_dd = min((d["value"] for d in drawdown_curve), default=0.0) + + # 日收益序列算 Sharpe (年化) + daily_rets = daily["avg_ret"].to_numpy() + sharpe = ( + float(daily_rets.mean() / daily_rets.std() * np.sqrt(252)) + if daily_rets.size > 1 and daily_rets.std() > 0 else 0.0 + ) + + # 收益分布直方图: 按 [-20%, +20%] 分 21 档 (每档 2%), 超出归入首尾档 + lo, hi, nbins = -0.20, 0.20, 20 + clipped = np.clip(fwd, lo, hi) + counts, edges = np.histogram(clipped, bins=nbins, range=(lo, hi)) + dist = [ + { + "range": f"{(edges[i]*100):+.0f}~{(edges[i+1]*100):+.0f}%", + "count": int(counts[i]), + "ratio": round(float(counts[i] / fwd.size), 4) if fwd.size else 0.0, + } + for i in range(nbins) + ] + + stats = { + "mode": "full", + "n_candidates": int(fwd.size), + "n_days": int(daily.height), + "avg_daily_candidates": round(float(daily["n_cand"].mean()), 1), + "avg_return": round(float(fwd.mean()), 4), + "median_return": round(float(np.median(fwd)), 4), + "win_rate": round(float(wins.size / fwd.size), 4) if fwd.size else 0.0, + "profit_factor": round(avg_win / avg_loss, 2) if avg_loss > 0 else None, + "best": round(float(fwd.max()), 4), + "worst": round(float(fwd.min()), 4), + "total_return": round(float(total_return), 4), + "max_drawdown": round(float(max_dd), 4), + "sharpe": round(sharpe, 2), + "benchmark_return": round(float(benchmark_return), 4), + "excess": round(float(total_return - benchmark_return), 4), + "return_distribution": dist, + } + + return SimResult( + equity_curve=equity_curve, + drawdown_curve=drawdown_curve, + trades=[], + per_symbol_stats=[], + stats=stats, + ) + + # ── 向量化信号生成 ── + + @staticmethod + def _date_range_mask(panel: pl.DataFrame, start: date, end: date) -> pl.Series: + return panel.select( + ((pl.col("date") >= start) & (pl.col("date") <= end)).alias("_range") + )["_range"].fill_null(False).cast(pl.Boolean) + + def _build_candidate_filter_mask( + self, + panel: pl.DataFrame, + s: StrategyDef, + params: dict, + ) -> pl.Series: + """生成策略候选层 mask。filter_history/filter 决定候选池, 不包含 entry_signals。""" + false_mask = pl.Series("_candidate_filter", [False] * len(panel), dtype=pl.Boolean) + true_mask = pl.Series("_candidate_filter", [True] * len(panel), dtype=pl.Boolean) + + history_failed = False + # 优先: filter_history_fn 策略 (涨停/反包等多日形态, 与选股路径共用同一逻辑) + if s.filter_history_fn: + try: + hit_df = s.filter_history_fn(panel, params) + if hit_df is None or hit_df.is_empty(): + return false_mask + # 命中行 (symbol,date) → 转 panel 等长布尔 mask + hits = hit_df.select(["symbol", "date"]).unique() + marked = ( + panel.select(["symbol", "date"]) + .join( + hits.with_columns(pl.lit(True).alias("_hit")), + on=["symbol", "date"], + how="left", + ) + ) + return marked["_hit"].fill_null(False).cast(pl.Boolean) + except Exception as e: + history_failed = True + logger.warning("strategy filter_history_fn failed: %s", e) + # 失败则回退到 filter_fn (若存在) + + # 策略 filter_fn: 候选层 (filter_history 不可用或失败时) + if s.filter_fn: + try: + expr = s.filter_fn(panel, params) + if expr is not None: + result = panel.select(expr.alias("_candidate_filter")) + if not result.is_empty(): + return result["_candidate_filter"].fill_null(False).cast(pl.Boolean) + except Exception as e: + logger.warning("strategy filter_fn failed: %s", e) + return false_mask + + if history_failed: + return false_mask + + # 没有策略候选层时, 由 entry_signals 直接决定买点。 + return true_mask + + def _build_entry_mask_from_candidate( + self, + panel: pl.DataFrame, + candidate_mask: pl.Series, + s: StrategyDef, + entry_signals: list[str], + ) -> pl.Series: + """向量化生成买入掩码:候选层 AND 买点层;无买点时只用策略候选层。""" + signal_mask = self._build_signal_mask(panel, entry_signals, "_entry_signal") + if entry_signals: + return candidate_mask & signal_mask + if s.filter_history_fn or s.filter_fn: + return candidate_mask + return pl.Series("_entry", [False] * len(panel), dtype=pl.Boolean) + + def _build_entry_mask( + self, + panel: pl.DataFrame, + s: StrategyDef, + params: dict, + entry_signals: list[str], + ) -> pl.Series: + """兼容旧调用: 候选层 AND 买点层。""" + candidate_mask = self._build_candidate_filter_mask(panel, s, params) + return self._build_entry_mask_from_candidate(panel, candidate_mask, s, entry_signals) + + @staticmethod + def _build_signal_mask(panel: pl.DataFrame, signals: list[str], name: str) -> pl.Series: + """向量化合并信号列,多个信号 OR。支持内置 signal_ 与自定义 csg_ 前缀。""" + masks: list[pl.Series] = [] + for sig in signals: + # csg_ (自定义信号) 直接用;否则按 signal_ 解析 + col = sig if (sig.startswith("signal_") or sig.startswith("csg_")) else f"signal_{sig}" + if col in panel.columns: + masks.append(panel[col].fill_null(False).cast(pl.Boolean)) + + if not masks: + return pl.Series(name, [False] * len(panel), dtype=pl.Boolean) + + combined = masks[0] + for m in masks[1:]: + combined = combined | m + return combined + + def _build_benchmark_curve(self, start: date, end: date) -> list[dict]: + try: + df = self.engine.repo.get_index_daily(BENCHMARK_SYMBOL, start, end, columns=["date", "close"]) + except Exception as e: + logger.warning("load benchmark %s failed: %s", BENCHMARK_SYMBOL, e) + return [] + + if df.is_empty() or "close" not in df.columns: + return [] + + df = df.filter(pl.col("close").is_not_null() & (pl.col("close") > 0)).sort("date") + if df.is_empty(): + return [] + + return [ + { + "date": str(row["date"])[:10], + "value": round(float(row["close"]), 4), + "close": round(float(row["close"]), 4), + "name": "上证指数", + "symbol": BENCHMARK_SYMBOL, + } + for row in df.iter_rows(named=True) + if row["close"] is not None + ] + + # ── 工具 ── + + @staticmethod + def _effective_basic_filter(s: StrategyDef, overrides: dict) -> dict: + basic_filter = dict(s.basic_filter or {}) + override_filter = overrides.get("basic_filter") + if isinstance(override_filter, dict): + basic_filter.update(override_filter) + return basic_filter + + @staticmethod + def _effective_signals(overrides: dict, key: str, default: list[str]) -> list[str]: + value = overrides.get(key) + if isinstance(value, list): + return [str(v) for v in value if v] + return list(default or []) + + @staticmethod + def _override_value(overrides: dict, key: str, default): + if key in overrides: + return overrides.get(key) + return default + + @staticmethod + def _normalize_pct(value, min_value: float, max_value: float) -> float | None: + if value is None or value == "": + return None + try: + pct = abs(float(value)) + except (TypeError, ValueError): + return None + return min(max(pct, min_value), max_value) + + @staticmethod + def _normalize_score_range(min_value, max_value) -> tuple[float | None, float | None]: + def _bound(value) -> float | None: + if value is None or value == "": + return None + try: + score = float(value) + except (TypeError, ValueError): + return None + if not np.isfinite(score): + return None + return min(max(score, 0.0), 100.0) + + score_min = _bound(min_value) + score_max = _bound(max_value) + if score_min is not None and score_max is not None and score_min > score_max: + score_min, score_max = score_max, score_min + return score_min, score_max + + @staticmethod + def _normalize_params(params: dict, s: StrategyDef) -> dict: + normalized = dict(params) + for param in s.meta.get("params", []): + pid = param.get("id") + if not pid: + continue + value = normalized.get(pid, param.get("default")) + p_type = param.get("type") + if p_type in {"float", "int"}: + try: + num = float(value) + except (TypeError, ValueError): + num = float(param.get("default", 0) or 0) + if param.get("min") is not None: + num = max(num, float(param["min"])) + if param.get("max") is not None: + num = min(num, float(param["max"])) + normalized[pid] = int(num) if p_type == "int" else num + elif p_type == "select" and param.get("options"): + normalized[pid] = value if value in param["options"] else param.get("default") + elif p_type == "bool": + if isinstance(value, bool): + normalized[pid] = value + elif isinstance(value, str): + normalized[pid] = value.lower() == "true" + else: + normalized[pid] = bool(param.get("default", False)) + else: + normalized[pid] = value + return normalized + + @staticmethod + def _trade_to_dict(t) -> dict: + return { + "symbol": t.symbol, + "name": t.name, + "entry_date": str(t.entry_date) if isinstance(t.entry_date, date) else str(t.entry_date), + "exit_date": str(t.exit_date) if isinstance(t.exit_date, date) else str(t.exit_date), + "entry_price": t.entry_price, + "exit_price": t.exit_price, + "pnl_pct": t.pnl_pct, + "duration": t.duration, + "exit_reason": t.exit_reason, + "shares": t.shares, + "lots": t.lots, + "position_pct": t.position_pct, + "entry_value": t.entry_value, + "exit_value": t.exit_value, + "pnl_amount": t.pnl_amount, + "entry_score": getattr(t, "entry_score", None), + "entry_signal_date": str(t.entry_signal_date) if getattr(t, "entry_signal_date", None) is not None else None, + "exit_signal_date": str(t.exit_signal_date) if getattr(t, "exit_signal_date", None) is not None else None, + "blocked_exit_days": getattr(t, "blocked_exit_days", 0), + } + + @staticmethod + def _config_to_dict(c: StrategyBacktestConfig) -> dict: + score_min, score_max = StrategyBacktestService._normalize_score_range( + (c.overrides or {}).get("score_min"), + (c.overrides or {}).get("score_max"), + ) + return { + "strategy_id": c.strategy_id, + "symbols": c.symbols, + "start": str(c.start), + "end": str(c.end), + "params": c.params, + "overrides": c.overrides, + "score_min": score_min, + "score_max": score_max, + "matching": c.matching, + "fees_pct": c.fees_pct, + "slippage_bps": c.slippage_bps, + "max_positions": c.max_positions, + "max_exposure_pct": c.max_exposure_pct, + "initial_capital": c.initial_capital, + "position_sizing": c.position_sizing, + "mode": c.mode, + "holding_days": c.holding_days, + } + + @staticmethod + def _apply_score( + panel: pl.DataFrame, + s: StrategyDef, + overrides: dict | None, + universe_mask: pl.Series | None = None, + ) -> pl.DataFrame: + scoring = s.meta.get("scoring", {}) + scoring_overrides = (overrides or {}).get("scoring") + if scoring_overrides: + scoring = {**scoring, **scoring_overrides} + + work = panel + has_universe = universe_mask is not None and len(universe_mask) == len(panel) + if has_universe: + work = work.with_columns(universe_mask.rename("_score_universe")) + + def _value_in_universe(col: str) -> pl.Expr: + if has_universe: + return pl.when(pl.col("_score_universe")).then(pl.col(col)).otherwise(None) + return pl.col(col) + + def _finish(df: pl.DataFrame) -> pl.DataFrame: + return df.drop("_score_universe") if "_score_universe" in df.columns else df + + if scoring: + total_weight = sum(scoring.values()) + if total_weight > 0: + score_parts: list[pl.Expr] = [] + for col, weight in scoring.items(): + if col not in work.columns: + continue + w = weight / total_weight + value = _value_in_universe(col) + col_min = value.min().over("date") + col_max = value.max().over("date") + col_range = col_max - col_min + normalized = pl.when(col_range > 0).then( + (pl.col(col) - col_min) / col_range + ).otherwise(pl.lit(0.5)) + if has_universe: + normalized = pl.when(pl.col("_score_universe")).then(normalized).otherwise(0.0) + score_parts.append(normalized * w) + if score_parts: + score_expr = score_parts[0] + for part in score_parts[1:]: + score_expr = score_expr + part + return _finish(work.with_columns((score_expr * 100).fill_null(0).alias("score"))) + + order_by = s.meta.get("order_by") + if order_by and order_by != "score" and order_by in work.columns: + direction = 1 if s.meta.get("descending", True) else -1 + score_expr = pl.col(order_by).fill_null(0) * direction + if has_universe: + score_expr = pl.when(pl.col("_score_universe")).then(score_expr).otherwise(0.0) + return _finish(work.with_columns(score_expr.alias("score"))) + return _finish(work.with_columns(pl.lit(0.0).alias("score"))) diff --git a/backend/app/config.py b/backend/app/config.py new file mode 100644 index 0000000..8468076 --- /dev/null +++ b/backend/app/config.py @@ -0,0 +1,61 @@ +"""全局配置 — 从环境变量 / .env 读取。""" +from __future__ import annotations + +from pathlib import Path + +from pydantic import Field, model_validator +from pydantic_settings import BaseSettings, SettingsConfigDict + +# 项目根目录 = backend/ 的父目录 +_BACKEND_DIR = Path(__file__).resolve().parent.parent +_PROJECT_ROOT = _BACKEND_DIR.parent + + +class Settings(BaseSettings): + model_config = SettingsConfigDict( + env_file=str(_PROJECT_ROOT / ".env"), + env_file_encoding="utf-8", + extra="ignore", + ) + + # TickFlow + tickflow_api_key: str = Field(default="", description="留空启用 free 模式") + + # AI + ai_provider: str = "openai_compat" + ai_base_url: str = "https://api.alysc.top" + ai_api_key: str = "" + ai_model: str = "gpt-5.5" + ai_daily_token_budget: int = 5_000_000 + + # Server + host: str = "0.0.0.0" + port: int = 3018 + log_level: str = "INFO" + backtest_range_guard: bool = False + + # Data — 默认使用项目根目录的 data/,可通过 DATA_DIR 环境变量覆盖 + data_dir: Path = _PROJECT_ROOT / "data" + + # tiers.yaml 路径(项目根目录) + tiers_yaml: Path = _PROJECT_ROOT / "tiers.yaml" + + # 静态文件(前端 dist) — 部署时只需 rsync 到 frontend/dist + static_dir: Path = _PROJECT_ROOT / "frontend" / "dist" + + @model_validator(mode="after") + def _resolve_paths(self) -> Settings: + """确保 data_dir 是绝对路径(环境变量传入的相对路径基于项目根目录解析)。""" + if not self.data_dir.is_absolute(): + # 相对路径基于项目根目录解析,而非 CWD + self.data_dir = (_PROJECT_ROOT / self.data_dir).resolve() + return self + + @property + def use_free_mode(self) -> bool: + """是否走 Free 模式。优先看 secrets.json,其次看 .env。""" + from app import secrets_store + return not secrets_store.get_tickflow_key() + + +settings = Settings() diff --git a/backend/app/indicators/__init__.py b/backend/app/indicators/__init__.py new file mode 100644 index 0000000..47c096f --- /dev/null +++ b/backend/app/indicators/__init__.py @@ -0,0 +1 @@ +"""技术指标 — Polars 实现(§7.5 / §7.7)。""" diff --git a/backend/app/indicators/pipeline.py b/backend/app/indicators/pipeline.py new file mode 100644 index 0000000..dcab138 --- /dev/null +++ b/backend/app/indicators/pipeline.py @@ -0,0 +1,1494 @@ +"""enriched 表计算流水线(§7.5 / §7.7 Step 2)。 + +存储层 (enriched parquet): + 仅存储基础行情窄表 (14 列), 指标和信号由各服务即时计算。 + + 存储列: symbol, date, OHLCV(前复权), volume, amount, + raw_close, raw_high, raw_low, turnover_rate, + consecutive_limit_ups, consecutive_limit_downs + +设计: + - 100% Polars 表达式(SQL 窗口无法表达递归 EMA) + - 每只标的独立计算(`.over("symbol")`) + - 有 adj_factor 时先应用前复权再算指标;无因子时直接用 raw + - streaming collect 控制内存 +""" +from __future__ import annotations + +import logging +from collections.abc import Callable +from pathlib import Path + +import polars as pl + +from app.config import settings + +logger = logging.getLogger(__name__) + + +# ── 自定义信号缓存 ───────────────────────────────────── +# 从 data/user_data/custom_signals/*.json 加载并编译为 Polars 表达式。 +# 模块级缓存:首次调用时加载,invalidate_custom_signals() 后下次重载。 +_custom_signal_exprs: dict[str, pl.Expr] | None = None + + +def _get_custom_signal_exprs() -> dict[str, pl.Expr]: + """懒加载自定义信号表达式(带模块级缓存)。""" + global _custom_signal_exprs + if _custom_signal_exprs is None: + from app.strategy import custom_signals + try: + sigs = custom_signals.load_all(settings.data_dir) + _custom_signal_exprs = custom_signals.build_expressions(sigs) + except Exception as e: + logger.warning("custom signals load failed: %s", e) + _custom_signal_exprs = {} + return _custom_signal_exprs + + +def invalidate_custom_signals() -> None: + """失效自定义信号缓存(保存/删除信号后调用,下次计算重新加载)。""" + global _custom_signal_exprs + _custom_signal_exprs = None + + +# enriched parquet 仅存储的列 (14 列) +ENRICHED_STORAGE_COLS = [ + "symbol", "date", + "open", "high", "low", "close", # 前复权 + "volume", "amount", + "raw_close", "raw_high", "raw_low", # 不复权原始价 + "turnover_rate", # 依赖当时的 float_shares, 不可回推 + "consecutive_limit_ups", # 递推状态, 需从历史 cum_sum + "consecutive_limit_downs", +] + + +# ================================================================ +# enriched 完整列清单 (存储 + 运行时计算) +# 供 AI 审查代码时参考: 策略/筛选/回测 可直接使用以下列名。 +# 分类: 存储列 → 指标列 → 信号列 → JOIN 列 +# ================================================================ +ENRICHED_COLUMNS: dict[str, dict[str, str]] = { + # ── 存储列 (parquet 持久化) ────────────────────────── + "symbol": "股票代码", + "date": "交易日期", + "open": "前复权开盘价", + "high": "前复权最高价", + "low": "前复权最低价", + "close": "前复权收盘价", + "volume": "成交量", + "amount": "成交额", + "raw_close": "原始收盘价(未复权)", + "raw_high": "原始最高价(未复权)", + "raw_low": "原始最低价(未复权)", + "turnover_rate": "换手率", + "consecutive_limit_ups": "连板数", + "consecutive_limit_downs": "连跌数", + # ── 基础指标 ───────────────────────────────────────── + "prev_close": "前收盘价", + "change_pct": "日涨跌幅(小数, 如 0.05 = 5%)", + "change_amount": "日涨跌额", + "amplitude": "日振幅 (最高-最低)/昨收", + # ── 均线 MA ────────────────────────────────────────── + "ma5": "5日简单均线", + "ma10": "10日简单均线", + "ma20": "20日简单均线", + "ma30": "30日简单均线", + "ma60": "60日简单均线(季线)", + # ── 指数均线 EMA ───────────────────────────────────── + "ema5": "5日指数均线", + "ema10": "10日指数均线", + "ema20": "20日指数均线", + "ema30": "30日指数均线", + "ema60": "60日指数均线", + # ── MACD ───────────────────────────────────────────── + "macd_dif": "MACD DIF线(快线-慢线)", + "macd_dea": "MACD DEA线(信号线)", + "macd_hist": "MACD柱状图 (DIF-DEA)×2", + # ── 布林带 BOLL ────────────────────────────────────── + "boll_upper": "布林带上轨 MA20+2σ", + "boll_lower": "布林带下轨 MA20-2σ", + # ── KDJ ────────────────────────────────────────────── + "kdj_k": "KDJ K值", + "kdj_d": "KDJ D值", + "kdj_j": "KDJ J值 (3K-2D)", + # ── ATR ────────────────────────────────────────────── + "atr_14": "14日平均真实波幅", + # ── 量价 ───────────────────────────────────────────── + "vol_ma5": "5日成交均量", + "vol_ma10": "10日成交均量", + "vol_ratio_5d": "量比 (成交量/5日均量)", + # ── 极值 ───────────────────────────────────────────── + "high_60d": "60日最高价", + "low_60d": "60日最低价", + # ── 动量 ───────────────────────────────────────────── + "momentum_5d": "5日动量(涨跌幅小数)", + "momentum_10d": "10日动量", + "momentum_20d": "20日动量", + "momentum_30d": "30日动量", + "momentum_60d": "60日动量", + # ── 波动率 ─────────────────────────────────────────── + "annual_vol_20d": "20日年化波动率", + # ── RSI ────────────────────────────────────────────── + "rsi_6": "6日相对强弱指标", + "rsi_14": "14日相对强弱指标", + "rsi_24": "24日相对强弱指标", + # ── 信号列 (bool) ──────────────────────────────────── + "signal_ma_golden_5_20": "MA5上穿MA20 (金叉)", + "signal_ma_dead_5_20": "MA5下穿MA20 (死叉)", + "signal_ma_golden_20_60": "MA20上穿MA60", + "signal_macd_golden": "MACD金叉 (DIF上穿DEA)", + "signal_macd_dead": "MACD死叉 (DIF下穿DEA)", + "signal_ma20_breakout": "收盘突破MA20上方", + "signal_ma20_breakdown": "收盘跌破MA20下方", + "signal_n_day_high": "创60日新高", + "signal_n_day_low": "创60日新低", + "signal_boll_breakout_upper": "突破布林上轨", + "signal_boll_breakdown_lower": "跌破布林下轨", + "signal_volume_surge": "放量 (量比≥2.0)", + "signal_limit_up": "涨停", + "signal_limit_down": "跌停", + "signal_limit_down_recovery": "跌停翘板(跌停后回升)", + "signal_broken_limit_up": "炸板(最高触及涨停但收盘未封住)", + # ── JOIN 列 (由 repository 从 instruments 表补充) ─── + "name": "股票名称 (来自 instruments)", + "total_shares": "总股本 (来自 instruments)", + "float_shares": "流通股本 (来自 instruments)", +} + +# 仅供 AI/开发者快速索引: 按类别的列名列表 +ENRICHED_COLUMNS_BY_CATEGORY: dict[str, list[str]] = { + "storage": [k for k in ENRICHED_COLUMNS if k in ENRICHED_STORAGE_COLS], + "basic": ["prev_close", "change_pct", "change_amount", "amplitude"], + "ma": ["ma5", "ma10", "ma20", "ma30", "ma60"], + "ema": ["ema5", "ema10", "ema20", "ema30", "ema60"], + "macd": ["macd_dif", "macd_dea", "macd_hist"], + "boll": ["boll_upper", "boll_lower"], + "kdj": ["kdj_k", "kdj_d", "kdj_j"], + "atr": ["atr_14"], + "volume": ["vol_ma5", "vol_ma10", "vol_ratio_5d"], + "extremes": ["high_60d", "low_60d"], + "momentum": ["momentum_5d", "momentum_10d", "momentum_20d", "momentum_30d", "momentum_60d"], + "volatility": ["annual_vol_20d"], + "rsi": ["rsi_6", "rsi_14", "rsi_24"], + "signals": [k for k in ENRICHED_COLUMNS if k.startswith("signal_")], + "join": ["name", "total_shares", "float_shares"], +} + + +def _ema_alpha(span: int) -> float: + return 2.0 / (span + 1) + + +def _math_half_up(expr: pl.Expr, decimals: int = 2) -> pl.Expr: + """交易所四舍五入 (round half up),替代 Python round()(银行家舍入)。 + + round(2.625, 2) = 2.62 ← Python 银行家舍入 + exchange_round(2.625) = 2.63 ← 交易所四舍五入 + """ + factor = 10 ** decimals + return (expr * factor + 0.5).floor() / factor + + +def _limit_price(prev: pl.Expr, limit_pct: pl.Expr, up: bool) -> pl.Expr: + """用「分」为单位的整数算术计算涨跌停价,规避浮点精度问题。 + + 交易所涨跌停价 = round(prev × (1 ± limit), 2),标准四舍五入。 + 若直接用浮点 prev × (1 ± limit) 会丢精度: + 18.90 × 0.95 = 17.955,浮点存储为 17.954999..., 四舍五入后得 17.95(错)。 + 本函数先把 prev 转成整数「分」(round 到分避免输入含厘误差), + 再用整数系数 105/95、110/90、120/80、130/70 相乘后四舍五入回元,全程不丢精度。 + """ + sign = 1 if up else -1 + # limit_pct ∈ {0.05, 0.10, 0.20, 0.30} → 系数分子 105/95、110/90、120/80、130/70 + num = ((1 + sign * limit_pct) * 100).cast(pl.Int64) # 105, 110, 120, 130 等 + cents = (prev * 100 + 0.5).floor().cast(pl.Int64) # 价格转「分」(四舍五入到分) + # cents × num / 100, 四舍五入到分(加 50) + return (((cents * num + 50) // 100) / 100) + + +def _apply_adj_factor(raw: pl.DataFrame, factors: pl.DataFrame) -> pl.DataFrame: + """对 raw K 线应用前复权 (forward adjustment)。 + + adj_factor 结构: symbol, trade_date, ex_factor + ex_factor 含义: 每次除权事件的 pre/post 比值(个股级,非累积)。 + + 前复权原理: + - 保持最新价格不变,将历史价格向下调整以消除除权缺口 + - adjusted = raw × cumprod_at_D / total_cumprod + - 等价于: adjusted = raw / (该日期之后所有事件的 ex_factor 乘积) + """ + if factors.is_empty(): + return raw + + # 确保类型一致 + factors = factors.with_columns( + pl.col("trade_date").cast(pl.Date, strict=False), + pl.col("ex_factor").cast(pl.Float64, strict=False), + ).select("symbol", "trade_date", "ex_factor").drop_nulls() + + if factors.is_empty(): + return raw + + # 去重 + 排序 + 累积乘积 (一趟完成) + factors_sorted = ( + factors.sort(["symbol", "trade_date"]) + .unique(subset=["symbol", "trade_date"]) + .sort(["symbol", "trade_date"]) + .with_columns( + pl.col("ex_factor").cum_prod().over("symbol").alias("cum_factor"), + ) + ) + + # 每个 symbol 的总累积因子 + total_factors = ( + factors_sorted + .group_by("symbol") + .agg(pl.col("cum_factor").last().alias("total_factor")) + ) + + raw_sorted = raw.sort(["symbol", "date"]) + + # join_asof backward: 每根 K 线取 <= 其 date 的最新累积因子 + # 同时带 trade_date 列用于判断除权日标记 + df = raw_sorted.join_asof( + factors_sorted.select("symbol", "trade_date", "cum_factor"), + left_on="date", + right_on="trade_date", + by="symbol", + strategy="backward", + ) + + # 补充 total_factor + 前复权 + 除权标记,一次 with_columns 完成 + df = df.join(total_factors, on="symbol", how="left") + + is_ex = pl.col("trade_date") == pl.col("date") + ratio = pl.col("cum_factor").fill_null(1.0) / pl.col("total_factor").fill_null(1.0) + price_cols = [c for c in ("open", "high", "low", "close") if c in df.columns] + + df = df.with_columns( + [pl.col(c) * ratio for c in price_cols] + + [ + is_ex.alias("ex_rights"), + ] + ).drop(["trade_date", "cum_factor", "total_factor"]) + + return df + + +# ================================================================ +# 技术指标计算 (从 OHLCV 计算) +# ================================================================ + +def compute_indicators(df: pl.DataFrame) -> pl.DataFrame: + """从 OHLCV 数据计算全套技术指标。 + + 输入必须包含: symbol, date, open, high, low, close, volume + 返回添加了所有指标列的 DataFrame。 + """ + if df.is_empty(): + return df + + import time as _time + _t0 = _time.perf_counter() + + df = df.sort(["symbol", "date"]) + + # Pass 1: 均线 + EMA + MACD 基础 + BOLL 基础 + KDJ 基础 + ATR 基础 + 量价 + 极值 + prev_close = pl.col("close").shift(1).over("symbol") + df = df.with_columns([ + # 前收盘价 + prev_close.alias("prev_close"), + # MA (最大 MA60) + pl.col("close").rolling_mean(5).over("symbol").alias("ma5"), + pl.col("close").rolling_mean(10).over("symbol").alias("ma10"), + pl.col("close").rolling_mean(20).over("symbol").alias("ma20"), + pl.col("close").rolling_mean(30).over("symbol").alias("ma30"), + pl.col("close").rolling_mean(60).over("symbol").alias("ma60"), + # EMA (不含 ema12/ema26, MACD 内部自算) + pl.col("close").ewm_mean(alpha=_ema_alpha(5), adjust=False).over("symbol").alias("ema5"), + pl.col("close").ewm_mean(alpha=_ema_alpha(10), adjust=False).over("symbol").alias("ema10"), + pl.col("close").ewm_mean(alpha=_ema_alpha(20), adjust=False).over("symbol").alias("ema20"), + pl.col("close").ewm_mean(alpha=_ema_alpha(30), adjust=False).over("symbol").alias("ema30"), + pl.col("close").ewm_mean(alpha=_ema_alpha(60), adjust=False).over("symbol").alias("ema60"), + # MACD base (内部计算, 不存 ema12/ema26) + pl.col("close").ewm_mean(alpha=_ema_alpha(12), adjust=False).over("symbol").alias("_ema12"), + pl.col("close").ewm_mean(alpha=_ema_alpha(26), adjust=False).over("symbol").alias("_ema26"), + # BOLL base + pl.col("close").rolling_std(20).over("symbol").alias("_boll_std"), + # KDJ base + pl.col("low").rolling_min(9).over("symbol").alias("_kdj_ln"), + pl.col("high").rolling_max(9).over("symbol").alias("_kdj_hn"), + # ATR base + pl.max_horizontal( + pl.col("high") - pl.col("low"), + (pl.col("high") - prev_close).abs(), + (pl.col("low") - prev_close).abs(), + ).alias("_tr"), + # 量价 base + pl.col("volume").rolling_mean(5).over("symbol").alias("vol_ma5"), + pl.col("volume").rolling_mean(10).over("symbol").alias("vol_ma10"), + pl.col("volume").rolling_mean(5).over("symbol").alias("_vol_ma5"), + # 极值 + pl.col("close").rolling_max(60).over("symbol").alias("high_60d"), + pl.col("close").rolling_min(60).over("symbol").alias("low_60d"), + ]) + + # Pass 2: MACD + BOLL (基于 Pass 1 基础列) + df = df.with_columns([ + (pl.col("_ema12") - pl.col("_ema26")).alias("macd_dif"), + (pl.col("ma20") + 2 * pl.col("_boll_std")).alias("boll_upper"), + (pl.col("ma20") - 2 * pl.col("_boll_std")).alias("boll_lower"), + ]).with_columns( + pl.col("macd_dif").ewm_mean(alpha=_ema_alpha(9), adjust=False).over("symbol").alias("macd_dea"), + ).with_columns( + ((pl.col("macd_dif") - pl.col("macd_dea")) * 2).alias("macd_hist"), + ) + + # Pass 3: KDJ + _kdj_rsv = ( + 100 * (pl.col("close") - pl.col("_kdj_ln")) + / (pl.col("_kdj_hn") - pl.col("_kdj_ln")).fill_null(1e-12) + ) + df = df.with_columns([ + _kdj_rsv.ewm_mean(alpha=1.0 / 3, adjust=False).over("symbol").alias("kdj_k"), + ]).with_columns([ + pl.col("kdj_k").ewm_mean(alpha=1.0 / 3, adjust=False).over("symbol").alias("kdj_d"), + ]).with_columns([ + (3 * pl.col("kdj_k") - 2 * pl.col("kdj_d")).alias("kdj_j"), + ]) + + # Pass 4: ATR + 量比 + 动量 + 波动 + 涨跌幅 + 涨跌额 + 振幅 + df = df.with_columns( + pl.col("_tr").ewm_mean(alpha=1.0 / 14, adjust=False).over("symbol").alias("atr_14"), + ).with_columns( + (pl.col("volume") / pl.col("_vol_ma5")).alias("vol_ratio_5d"), + ).with_columns([ + # 动量: 5d/10d/20d/30d/60d + (pl.col("close") / pl.col("close").shift(5).over("symbol") - 1).alias("momentum_5d"), + (pl.col("close") / pl.col("close").shift(10).over("symbol") - 1).alias("momentum_10d"), + (pl.col("close") / pl.col("close").shift(20).over("symbol") - 1).alias("momentum_20d"), + (pl.col("close") / pl.col("close").shift(30).over("symbol") - 1).alias("momentum_30d"), + (pl.col("close") / pl.col("close").shift(60).over("symbol") - 1).alias("momentum_60d"), + # 日涨跌幅 + (pl.col("close") / pl.col("close").shift(1).over("symbol") - 1).alias("change_pct"), + ]).with_columns( + # 涨跌额 + (pl.col("close") - pl.col("close").shift(1).over("symbol")).alias("change_amount"), + ).with_columns( + # 振幅 = (high - low) / prev_close + pl.when(pl.col("close").shift(1).over("symbol") > 0) + .then((pl.col("high") - pl.col("low")) / pl.col("close").shift(1).over("symbol")) + .otherwise(None) + .alias("amplitude"), + ).with_columns( + # 日涨跌幅 (用于波动率) + pl.col("close").pct_change().over("symbol").alias("_daily_pct"), + ).with_columns( + # 年化波动率 + (pl.col("_daily_pct").rolling_std(20).over("symbol") * (252 ** 0.5)) + .alias("annual_vol_20d"), + ) + + # Pass 5: RSI + df = df.with_columns( + pl.col("close").diff().over("symbol").alias("_delta"), + ).with_columns([ + pl.when(pl.col("_delta") > 0).then(pl.col("_delta")).otherwise(0.0).alias("_gain"), + pl.when(pl.col("_delta") < 0).then(-pl.col("_delta")).otherwise(0.0).alias("_loss"), + ]) + for n in (6, 14, 24): + a = 1.0 / n + df = df.with_columns([ + pl.col("_gain").ewm_mean(alpha=a, adjust=False).over("symbol").alias(f"_rsi_avg_gain_{n}"), + pl.col("_loss").ewm_mean(alpha=a, adjust=False).over("symbol").alias(f"_rsi_avg_loss_{n}"), + ]).with_columns( + (100 - 100 / (1 + pl.col(f"_rsi_avg_gain_{n}") / + pl.when(pl.col(f"_rsi_avg_loss_{n}") == 0) + .then(1e-12) + .otherwise(pl.col(f"_rsi_avg_loss_{n}")) + )).alias(f"rsi_{n}"), + ) + + # Pass 6: 换手率 (需要 float_shares, 后续在 compute_all 中 JOIN instruments 后补充) + + # 清理临时列 + df = df.drop(["_boll_std", "_tr", "_ema12", "_ema26", + "_kdj_ln", "_kdj_hn", "_vol_ma5", "_daily_pct", + "_delta", "_gain", "_loss", + "_rsi_avg_gain_6", "_rsi_avg_loss_6", + "_rsi_avg_gain_14", "_rsi_avg_loss_14", + "_rsi_avg_gain_24", "_rsi_avg_loss_24"]) + + _elapsed = (_time.perf_counter() - _t0) * 1000 + import logging as _logging + _logging.getLogger(__name__).debug("compute_indicators: %.1fms, %d rows", _elapsed, len(df)) + + return df + + +def compute_signals(df: pl.DataFrame) -> pl.DataFrame: + """从已有指标列计算原子信号布尔列。 + + 输入必须包含 compute_indicators() 产出的指标列。 + """ + if df.is_empty(): + return df + + df = df.with_columns([ + ((pl.col("ma5") > pl.col("ma20")) & + (pl.col("ma5").shift(1).over("symbol") <= pl.col("ma20").shift(1).over("symbol"))) + .alias("signal_ma_golden_5_20"), + ((pl.col("ma5") < pl.col("ma20")) & + (pl.col("ma5").shift(1).over("symbol") >= pl.col("ma20").shift(1).over("symbol"))) + .alias("signal_ma_dead_5_20"), + ((pl.col("ma20") > pl.col("ma60")) & + (pl.col("ma20").shift(1).over("symbol") <= pl.col("ma60").shift(1).over("symbol"))) + .alias("signal_ma_golden_20_60"), + ((pl.col("macd_dif") > pl.col("macd_dea")) & + (pl.col("macd_dif").shift(1).over("symbol") <= pl.col("macd_dea").shift(1).over("symbol"))) + .alias("signal_macd_golden"), + ((pl.col("macd_dif") < pl.col("macd_dea")) & + (pl.col("macd_dif").shift(1).over("symbol") >= pl.col("macd_dea").shift(1).over("symbol"))) + .alias("signal_macd_dead"), + ((pl.col("close") > pl.col("ma20")) & + (pl.col("close").shift(1).over("symbol") <= pl.col("ma20").shift(1).over("symbol"))) + .alias("signal_ma20_breakout"), + ((pl.col("close") < pl.col("ma20")) & + (pl.col("close").shift(1).over("symbol") >= pl.col("ma20").shift(1).over("symbol"))) + .alias("signal_ma20_breakdown"), + (pl.col("close") >= pl.col("high_60d")).alias("signal_n_day_high"), + (pl.col("close") <= pl.col("low_60d")).alias("signal_n_day_low"), + (pl.col("close") > pl.col("boll_upper")).alias("signal_boll_breakout_upper"), + (pl.col("close") < pl.col("boll_lower")).alias("signal_boll_breakdown_lower"), + (pl.col("vol_ratio_5d") >= 2.0).alias("signal_volume_surge"), + ]) + + # 自定义信号(用户配置的字段+运算符+值组合,编译为布尔列) + from app.strategy import custom_signals + df = custom_signals.inject(df, _get_custom_signal_exprs()) + + return df + + +def compute_limit_signals(df: pl.DataFrame, instruments: pl.DataFrame) -> pl.DataFrame: + """计算涨跌停相关信号。 + + 产出: + signal_limit_up, consecutive_limit_ups + signal_limit_down, consecutive_limit_downs + signal_limit_down_recovery (跌停翘板) + signal_broken_limit_up (炸板: 最高价触及涨停价但收盘未封住) + + 输入必须包含: symbol, date, raw_close, raw_high, open, high, low, close, + change_pct, vol_ratio_5d。 + """ + if df.is_empty(): + return df + + # 从 instruments 取 ST 标记 + 流通股本(换手率用) + inst_cols = ["symbol"] + if "name" in instruments.columns: + inst_cols.append("name") + if "float_shares" in instruments.columns: + inst_cols.append("float_shares") + inst_subset = instruments.select(inst_cols).unique(subset=["symbol"]) + + if "name" in instruments.columns: + st_flag = ( + instruments + .select("symbol", pl.col("name").str.contains("ST").alias("_is_st")) + .unique(subset=["symbol"]) + ) + inst_subset = inst_subset.join(st_flag, on="symbol", how="left") + + df = df.join(inst_subset, on="symbol", how="left", suffix="_inst") + + # 计算换手率(%) = volume(手) * 10000 / float_shares(股) + if "float_shares" in df.columns and "volume" in df.columns: + df = df.with_columns( + pl.when(pl.col("float_shares") > 0) + .then(pl.col("volume") * 10000.0 / pl.col("float_shares")) + .otherwise(None) + .alias("turnover_rate") + ) + elif "turnover_rate" not in df.columns: + df = df.with_columns(pl.lit(None).cast(pl.Float64).alias("turnover_rate")) + + # 前一日参考收盘价(交易所涨跌停基准价) + # 仅在 adj_factor 发生变化(除权除息 XD/DR)时使用前复权昨收作为交易所参考价; + # 否则使用原始 raw_close.shift(1) 以避免浮点精度误差。 + _adj_today = pl.col("close") / pl.col("raw_close") + _adj_yesterday = pl.col("close").shift(1).over("symbol") / pl.col("raw_close").shift(1).over("symbol") + _adj_changed = (_adj_today - _adj_yesterday).abs() > 1e-6 + df = df.with_columns( + pl.when(_adj_changed) + .then(pl.col("close").shift(1).over("symbol")) # 除权: 使用前复权昨收 + .otherwise(pl.col("raw_close").shift(1).over("symbol")) # 正常: 使用原始昨收 + .alias("_prev_raw_close") + ) + + # 板块涨跌停比例 + is_chinext = pl.col("symbol").str.starts_with("300") | pl.col("symbol").str.starts_with("301") + is_star = pl.col("symbol").str.starts_with("688") | pl.col("symbol").str.starts_with("689") + is_bj = pl.col("symbol").str.ends_with(".BJ") + + df = df.with_columns( + pl.when(is_chinext).then(0.20) + .when(is_star).then(0.20) + .when(is_bj).then(0.30) + .otherwise(0.10) + .alias("_board_pct") + ) + + # ST → 5%(覆盖板块默认值) + if "_is_st" in df.columns: + df = df.with_columns( + pl.when(pl.col("_is_st").fill_null(False)) + .then(0.05) + .otherwise(pl.col("_board_pct")) + .alias("_limit_pct") + ) + else: + df = df.with_columns(pl.col("_board_pct").alias("_limit_pct")) + + # 理论涨停价 = prev_close × (1 + limit_pct) 整数算术,避免浮点误差 + df = df.with_columns( + _limit_price(pl.col("_prev_raw_close"), pl.col("_limit_pct"), up=True) + .alias("_theoretical_limit_up") + ) + + # 理论跌停价 = prev_close × (1 - limit_pct) + df = df.with_columns( + _limit_price(pl.col("_prev_raw_close"), pl.col("_limit_pct"), up=False) + .alias("_theoretical_limit_down") + ) + + # ── signal_limit_up ── + df = df.with_columns( + pl.when( + pl.col("_prev_raw_close").is_not_null() + & (pl.col("_prev_raw_close") > 0) + & (pl.col("raw_close") > 0) + ).then( + (pl.col("raw_close") - pl.col("_theoretical_limit_up")).abs() < 0.005 + ).otherwise(None).cast(pl.Boolean) + .alias("signal_limit_up") + ) + + # ── consecutive_limit_ups ── + df = df.with_columns( + (~pl.col("signal_limit_up").fill_null(False)) + .cast(pl.UInt32) + .cum_sum() + .over("symbol") + .alias("_grp_up") + ).with_columns( + pl.col("signal_limit_up") + .cast(pl.UInt32) + .cum_sum() + .over("symbol", "_grp_up") + .cast(pl.UInt32) + .alias("consecutive_limit_ups") + ).with_columns( + pl.when(pl.col("signal_limit_up").fill_null(False)) + .then(pl.col("consecutive_limit_ups")) + .otherwise(0) + .cast(pl.UInt32) + .alias("consecutive_limit_ups") + ) + + # ── signal_limit_down ── + df = df.with_columns( + pl.when( + pl.col("_prev_raw_close").is_not_null() + & (pl.col("_prev_raw_close") > 0) + & (pl.col("raw_close") > 0) + ).then( + (pl.col("raw_close") - pl.col("_theoretical_limit_down")).abs() < 0.005 + ).otherwise(None).cast(pl.Boolean) + .alias("signal_limit_down") + ) + + # ── consecutive_limit_downs ── + df = df.with_columns( + (~pl.col("signal_limit_down").fill_null(False)) + .cast(pl.UInt32) + .cum_sum() + .over("symbol") + .alias("_grp_down") + ).with_columns( + pl.col("signal_limit_down") + .cast(pl.UInt32) + .cum_sum() + .over("symbol", "_grp_down") + .cast(pl.UInt32) + .alias("consecutive_limit_downs") + ).with_columns( + pl.when(pl.col("signal_limit_down").fill_null(False)) + .then(pl.col("consecutive_limit_downs")) + .otherwise(0) + .cast(pl.UInt32) + .alias("consecutive_limit_downs") + ) + + # ── signal_limit_down_recovery (跌停翘板) ── + # 条件: 当日最低价曾触及跌停价 + 最终没有跌停 + 收阳 + df = df.with_columns( + pl.when( + pl.col("_prev_raw_close").is_not_null() + & (pl.col("_prev_raw_close") > 0) + ).then( + (~pl.col("signal_limit_down").fill_null(False)) # 最终没跌停 + & (pl.col("low") <= pl.col("_theoretical_limit_down") + 0.005) # 曾触及跌停 + & (pl.col("close") > pl.col("open")) # 收阳 + ).otherwise(None).cast(pl.Boolean) + .alias("signal_limit_down_recovery") + ) + + # ── signal_broken_limit_up (炸板) ── + # 条件: 最高价曾触及涨停价 + 最终没有封住涨停 + df = df.with_columns( + pl.when( + pl.col("_prev_raw_close").is_not_null() + & (pl.col("_prev_raw_close") > 0) + & (pl.col("raw_high") > 0) + ).then( + (~pl.col("signal_limit_up").fill_null(False)) # 最终没封住涨停 + & (pl.col("raw_high") >= pl.col("_theoretical_limit_up") - 0.005) # 曾触及涨停价 + ).otherwise(None).cast(pl.Boolean) + .alias("signal_broken_limit_up") + ) + + # 清理临时列 + JOIN 引入的 instruments 列 (不存入 enriched) + cleanup = ["_prev_raw_close", "_board_pct", "_limit_pct", + "_theoretical_limit_up", "_theoretical_limit_down", + "_grp_up", "_grp_down"] + if "_is_st" in df.columns: + cleanup.append("_is_st") + # 清理 join 产生的重复列 + for c in df.columns: + if c.endswith("_inst"): + cleanup.append(c) + # name 和 float_shares 只用于计算, 不存入 enriched + for c in ["name", "float_shares"]: + if c in df.columns and c != "turnover_rate": + cleanup.append(c) + df = df.drop([c for c in cleanup if c in df.columns]) + + return df + + +def compute_all(df: pl.DataFrame, instruments: pl.DataFrame | None = None) -> pl.DataFrame: + """从 OHLCV 计算全套指标 + 信号。一站式调用。 + + 输入: symbol, date, open, high, low, close, volume, amount, raw_close + """ + df = compute_indicators(df) + df = compute_signals(df) + if instruments is not None and not instruments.is_empty(): + df = compute_limit_signals(df, instruments) + + # 清理 NaN / Inf + float_cols = [c for c in df.columns if df[c].dtype.is_float()] + if float_cols: + df = df.with_columns([ + pl.when(pl.col(c).is_nan() | pl.col(c).is_infinite()) + .then(None) + .otherwise(pl.col(c)) + .alias(c) + for c in float_cols + ]) + + return df + + +def filter_halt_days(df: pl.DataFrame) -> pl.DataFrame: + """过滤停牌日。 + + 停牌日的 open/high 必然为 0 (无集合竞价)。注意 close 可能被数据源 + 填充为前收盘价而非 0, 因此不能用 "OHLC 全零" 判断, 否则会漏过这类 + 停牌记录 (如 *ST 撤销风险警示的停牌日), 污染 MA/ATR 等指标。 + """ + if df.is_empty() or "open" not in df.columns or "high" not in df.columns: + return df + return df.filter(~((pl.col("open") == 0) & (pl.col("high") == 0))) + + +# ================================================================ +# Pipeline: 盘后全量计算 + 写入 +# ================================================================ + +def compute_enriched( + raw: pl.DataFrame, + factors: pl.DataFrame | None = None, + instruments: pl.DataFrame | None = None, +) -> pl.DataFrame: + """对原始日 K 应用前复权 + 全量计算指标 + 信号, 产出完整 enriched (含全部指标列)。 + + 输入应包含至少: symbol, date, open, high, low, close, volume (可选 amount)。 + 如果提供了 factors, 先应用前复权再算指标。 + 如果提供了 instruments, 计算涨跌停信号和换手率。 + """ + if raw.is_empty(): + return raw + + # 过滤停牌日 (会污染指标计算) + raw = filter_halt_days(raw) + + if raw.is_empty(): + return raw + + # 保留不复权原始价格(涨停/炸板/跌停判断需用不复权价格) + raw = raw.with_columns( + pl.col("close").alias("raw_close"), + pl.col("high").alias("raw_high"), + pl.col("low").alias("raw_low"), + ) + + # 应用前复权(只改 open/high/low/close,raw_close 不受影响) + if factors is not None and not factors.is_empty(): + raw = _apply_adj_factor(raw, factors) + + # 排序 + df = raw.sort(["symbol", "date"]) + + # 全量计算指标 + 信号 + df = compute_all(df, instruments=instruments) + + return df + + +def _select_storage_cols(df: pl.DataFrame) -> pl.DataFrame: + """写入 parquet 前裁剪到存储列 (14 列)。""" + cols = [c for c in ENRICHED_STORAGE_COLS if c in df.columns] + return df.select(cols) + + +def run_pipeline(data_dir: Path | None = None, + symbols: list[str] | None = None, + new_dates_only: bool = False, + on_batch_done: Callable[[int, int], None] | None = None) -> int: + """运行盘后管道:读 kline_daily + adj_factor → 前复权 + 计算存储列 → 写 enriched。 + + enriched 表仅存储 14 列基础行情窄表 (OHLCV + raw_close/high/low + turnover_rate + 连板数)。 + + 模式: + - 全量 (symbols=None, new_dates_only=False): + 读全部 kline_daily, 全部重写 enriched 分区。 + 用于首次同步、往前扩展历史。 + - 向后增量 (new_dates_only=True): + 只读 enriched 中尚不存在的日期分区对应的 daily 数据, + 为所有标的生成新的 enriched 分区; + 若同时传 symbols, 还会对这些个股的全部已有日期做重算 + (因为除权因子链变了,历史数据的复权比例也要更新)。 + - 除权因子增量 (symbols 指定, new_dates_only=False): + 只对指定 symbol 做局部重算并合并回已有 enriched。 + 用于无新日K数据、仅除权因子变更的场景。 + 返回写入的行数。 + """ + import time as _t + t0 = _t.perf_counter() + + d = Path(data_dir or settings.data_dir) + daily_dir = d / "kline_daily" + enriched_base = d / "kline_daily_enriched" + factor_path = d / "adj_factor" / "all.parquet" + inst_glob = str(d / "instruments" / "**" / "*.parquet") + + if not daily_dir.exists() or not any(daily_dir.rglob("*.parquet")): + logger.info("无日K数据, 跳过管道") + return 0 + + daily_glob = (daily_dir / "**" / "*.parquet").as_posix() + _cast = pl.ScanCastOptions(integer_cast="allow-float") + written = 0 + + # 加载 instruments (涨跌停+换手率需要) + instruments = pl.DataFrame() + try: + instruments = pl.scan_parquet(inst_glob, cast_options=_cast).collect() + except Exception as e: # noqa: BLE001 + logger.warning("instruments 读取失败: %s", e) + + if new_dates_only: + # ── 向后增量模式 ── + # 1. 找出 daily 有但 enriched 还没有的日期 + enriched_dates = set() + if enriched_base.exists(): + enriched_dates = {p.stem.split("=")[1] for p in enriched_base.glob("date=*")} + + # 读新增日期的 daily 数据 (所有标的) + new_date_dirs = sorted( + p for p in daily_dir.glob("date=*") + if p.stem.split("=")[1] not in enriched_dates + ) + if not new_date_dirs and not symbols: + logger.info("增量模式: 无新日期, 无需重算") + return 0 + + # 加载复权因子 (全量,因为所有标的都可能需要) + factors = _load_factors(factor_path) + + # 2. 为新日期计算 enriched (所有标的) + if new_date_dirs: + raw_new = pl.scan_parquet(new_date_dirs[0] / "*.parquet", cast_options=_cast) + for nd in new_date_dirs[1:]: + raw_new = pl.concat([raw_new, pl.scan_parquet(nd / "*.parquet", cast_options=_cast)], how="diagonal_relaxed") + raw_new = raw_new.sort(["symbol", "date"]).collect(streaming=True) + + # 增量模式: 只算新日期, 但指标需要历史窗口 + # 读已有 enriched 最近 60 天作为历史前缀 + sym_list = raw_new["symbol"].unique().to_list() + hist_df = _load_recent_history(enriched_base, sym_list, days=60) + + # 合并历史 + 新数据 + if not hist_df.is_empty(): + # 只取基础行情列做历史前缀 + hist_cols = [c for c in ["symbol", "date", "open", "high", "low", "close", + "volume", "amount", "raw_close", "raw_high", "raw_low"] + if c in hist_df.columns] + raw_full = pl.concat([hist_df.select(hist_cols), raw_new], how="diagonal_relaxed") + else: + raw_full = raw_new + + enriched_new = compute_enriched(raw_full, factors=factors, instruments=instruments) + + # 只保留新日期的行 + new_date_set = set() + for nd in new_date_dirs: + ds = nd.stem.split("=")[1] + new_date_set.add(ds) + enriched_new = enriched_new.filter( + pl.col("date").map_elements(lambda x: x.isoformat(), return_dtype=pl.Utf8).is_in(list(new_date_set)) + ) + + t_new = _t.perf_counter() + logger.info("增量计算: %d 个新日期, %d 行, 耗时 %.2fs", + len(new_date_dirs), enriched_new.height, t_new - t0) + + if not enriched_new.is_empty(): + for date_df in enriched_new.partition_by("date"): + dt = date_df["date"][0] + ds = dt.isoformat() if hasattr(dt, "isoformat") else str(dt) + out = enriched_base / f"date={ds}" / "part.parquet" + out.parent.mkdir(parents=True, exist_ok=True) + date_df = _select_storage_cols(date_df).sort(["symbol"]) + date_df.write_parquet(out) + written += date_df.height + t_write_new = _t.perf_counter() + logger.info("增量写入: %.2fs, %d 行", t_write_new - t_new, written) + + # 3. 受除权因子影响的个股: 重算全部已有日期 (累积因子链变了) + if symbols: + sym_set = set(symbols) + raw_sym = pl.scan_parquet(daily_glob, cast_options=_cast).sort(["symbol", "date"]) + raw_sym = raw_sym.filter(pl.col("symbol").is_in(list(sym_set))) + raw_sym = raw_sym.collect(streaming=True) + if not raw_sym.is_empty(): + factors_sym = factors.filter(pl.col("symbol").is_in(list(sym_set))) if not factors.is_empty() else factors + inst_sym = instruments.filter(pl.col("symbol").is_in(list(sym_set))) if not instruments.is_empty() else instruments + enriched_sym = compute_enriched(raw_sym, factors=factors_sym, instruments=inst_sym) + for date_df in enriched_sym.partition_by("date"): + dt = date_df["date"][0] + ds = dt.isoformat() if hasattr(dt, "isoformat") else str(dt) + out = enriched_base / f"date={ds}" / "part.parquet" + out.parent.mkdir(parents=True, exist_ok=True) + date_df_storage = _select_storage_cols(date_df) + if out.exists(): + existing = pl.read_parquet(out) + existing = existing.filter(~pl.col("symbol").is_in(list(sym_set))) + date_df_storage = pl.concat([existing, date_df_storage], how="diagonal_relaxed") + date_df_storage = date_df_storage.sort(["symbol"]) + date_df_storage.write_parquet(out) + written += date_df.height + logger.info("除权重算: %d 只, 共写入 %d 行", len(sym_set), written) + + t_done = _t.perf_counter() + logger.info("增量管道完成: %.2fs, %d 行", t_done - t0, written) + return written + + # ── 全量 或 除权因子增量 模式 ── + mode = f"incremental ({len(symbols)} symbols)" if symbols else "full" + base = d / "kline_daily_enriched" + + # 加载复权因子 (全量加载一次,每批复用) + factors = _load_factors(factor_path) + + # 局部模式: 过滤 instruments + inst_use = instruments + + import gc + + # ── 按 symbol 分批处理: 每只股只有 ~244 行, 无冗余计算 ── + # 先获取全部 symbol 列表 + lf_all = pl.scan_parquet(daily_glob, cast_options=_cast) + if symbols: + sym_set = set(symbols) + lf_all = lf_all.filter(pl.col("symbol").is_in(list(sym_set))) + + all_symbols = ( + lf_all.select("symbol").unique().sort("symbol") + .collect(streaming=True)["symbol"].to_list() + ) + if not all_symbols: + logger.info("无日K数据, 跳过管道") + return 0 + + total_syms = len(all_symbols) + logger.info("全量计算: %d 只标的, 按 symbol 分批 [%s]", total_syms, mode) + + if not factors.is_empty() and symbols: + factors = factors.filter(pl.col("symbol").is_in(list(sym_set))) + if not factors.is_empty(): + logger.info("读取复权因子: %d 行", factors.height) + if not instruments.is_empty() and symbols: + inst_use = instruments.filter(pl.col("symbol").is_in(list(sym_set))) + + from app.services import preferences as prefs_mod + SYM_BATCH = prefs_mod.get_enriched_batch_size() # 每批 N 只 × ~244 天, 可在设置中调整 + total_batches = (total_syms + SYM_BATCH - 1) // SYM_BATCH + + # 全量模式: 先清理旧 enriched 目录, 最后一次性按日期写入 + # 收集所有批次结果, 按日期分区写入 + from collections import defaultdict + date_buffers: dict[str, list[pl.DataFrame]] = defaultdict(list) + + for batch_start in range(0, total_syms, SYM_BATCH): + batch_end = min(batch_start + SYM_BATCH, total_syms) + batch_syms = all_symbols[batch_start:batch_end] + + # 只读取本批 symbol 的数据 + lf_batch = pl.scan_parquet(daily_glob, cast_options=_cast) + lf_batch = lf_batch.filter(pl.col("symbol").is_in(batch_syms)) + raw = lf_batch.sort(["symbol", "date"]).collect(streaming=True) + + if raw.is_empty(): + continue + + # 本批的 factors / instruments + batch_factors = ( + factors.filter(pl.col("symbol").is_in(batch_syms)) + if not factors.is_empty() else factors + ) + batch_inst = ( + inst_use.filter(pl.col("symbol").is_in(batch_syms)) + if not inst_use.is_empty() else inst_use + ) + + # 计算 + enriched = compute_enriched(raw, factors=batch_factors, instruments=batch_inst) + + if not enriched.is_empty(): + if symbols: + # 局部模式: 直接按日期合并写入 + for date_df in enriched.partition_by("date"): + dt = date_df["date"][0] + ds = dt.isoformat() if hasattr(dt, "isoformat") else str(dt) + out = base / f"date={ds}" / "part.parquet" + out.parent.mkdir(parents=True, exist_ok=True) + date_df_storage = _select_storage_cols(date_df) + if out.exists(): + existing = pl.read_parquet(out) + existing = existing.filter(~pl.col("symbol").is_in(batch_syms)) + date_df_storage = pl.concat([existing, date_df_storage], how="diagonal_relaxed") + date_df_storage = date_df_storage.sort(["symbol"]) + date_df_storage.write_parquet(out) + written += date_df_storage.height + else: + # 全量模式: 缓冲到 date_buffers, 最后一次性写入 + for date_df in enriched.partition_by("date"): + dt = date_df["date"][0] + ds = dt.isoformat() if hasattr(dt, "isoformat") else str(dt) + date_buffers[ds].append(_select_storage_cols(date_df).sort(["symbol"])) + written += date_df.height + + del raw, enriched, batch_factors, batch_inst + gc.collect() + + logger.info("symbol 批次 %d/%d (%s ~ %s), 已处理 %d 行", + batch_start // SYM_BATCH + 1, + total_batches, + batch_syms[0], batch_syms[-1], written) + + # 通知进度 + if on_batch_done: + on_batch_done(batch_start // SYM_BATCH + 1, total_batches) + + # 全量模式: 按日期分区写入 + if not symbols and date_buffers: + if base.exists(): + import shutil + shutil.rmtree(base) + base.mkdir(parents=True, exist_ok=True) + + for ds, dfs in date_buffers.items(): + out = base / f"date={ds}" / "part.parquet" + out.parent.mkdir(parents=True, exist_ok=True) + merged = pl.concat(dfs, how="diagonal_relaxed").sort(["symbol"]) + merged.write_parquet(out) + + date_buffers.clear() + gc.collect() + + t_done = _t.perf_counter() + adj_label = "含复权" if not factors.is_empty() else "无复权" + logger.info("enriched 完成 [%s]: %.2fs, 共 %d 行, %s", + mode, t_done - t0, written, adj_label) + return written + + +def _load_factors(factor_path: Path) -> pl.DataFrame: + """加载复权因子文件。""" + if not factor_path.exists(): + return pl.DataFrame() + try: + return pl.read_parquet(factor_path) + except Exception as e: # noqa: BLE001 + logger.warning("复权因子读取失败: %s", e) + return pl.DataFrame() + + +def _load_recent_history(enriched_base: Path, symbols: list[str], days: int) -> pl.DataFrame: + """从已有 enriched parquet 加载最近 N 天的历史数据(用于增量模式的指标计算窗口)。 + + 只读基础行情列, 作为指标计算的历史前缀。 + """ + from datetime import date, timedelta + cutoff = date.today() - timedelta(days=days + 30) # 多读 30 天余量 + + try: + lf = ( + pl.scan_parquet(str(enriched_base / "**" / "*.parquet"), cast_options=_cast) + .filter( + (pl.col("symbol").is_in(symbols)) + & (pl.col("date") >= cutoff) + ) + .sort(["symbol", "date"]) + ) + hist_cols = [c for c in ["symbol", "date", "open", "high", "low", "close", + "volume", "amount", "raw_close", "raw_high", "raw_low"] + if c in lf.schema] + return lf.select(hist_cols).collect() + except Exception as e: # noqa: BLE001 + logger.warning("历史数据加载失败: %s", e) + return pl.DataFrame() + + +def compute_enriched_single(daily_for_symbol: pl.DataFrame) -> pl.DataFrame: + """单股版本 — Free 用户用,拉下来单股 K 后即时计算全部指标+信号返回给前端。""" + if daily_for_symbol.is_empty(): + return daily_for_symbol + + # 过滤停牌 + daily_for_symbol = filter_halt_days(daily_for_symbol) + if daily_for_symbol.is_empty(): + return daily_for_symbol + + # 保留 raw_close 用于涨停判断 + daily_for_symbol = daily_for_symbol.with_columns(pl.col("close").alias("raw_close")) + + # 即时计算全套指标 + 信号 (无复权因子, 无 instruments) + return compute_all(daily_for_symbol) + + +# ================================================================ +# 盘中增量计算: 只算今天 5500 行 (不复算历史) +# ================================================================ + +def compute_enriched_today( + live_agg: pl.DataFrame, + prev_enriched: pl.DataFrame, + today_ohlcv: pl.DataFrame, + instruments: pl.DataFrame | None = None, +) -> pl.DataFrame: + """用昨天的递推状态 + 今天的 OHLCV 增量计算今天的 enriched 数据。 + + 只处理 ~5500 行, 耗时 ~10-50ms (替代全量 compute_enriched 的 1.5-2s)。 + + 参数: + live_agg: repo.get_live_agg() — 包含所有递推状态 + 窗口聚合 + prev_enriched: repo.get_enriched_latest() — 昨天的完整 enriched (用于信号交叉判断) + today_ohlcv: 今天的 OHLCV (symbol, date, open, high, low, close, volume, amount) + instruments: 维表 (涨跌停/换手率需要) + + 返回: + 今天的 enriched DataFrame (~5500 行, 64 列) + """ + if today_ohlcv.is_empty() or live_agg.is_empty(): + return pl.DataFrame() + + alpha = _ema_alpha + + # ---- JOIN: 今天的 OHLCV + 昨天的递推状态 ---- + df = today_ohlcv.join(live_agg, on="symbol", how="inner") + + # ---- 前复权: 保存原始价 → 调整 OHLCV ---- + df = df.with_columns([ + pl.col("close").alias("raw_close"), + pl.col("high").alias("raw_high"), + pl.col("low").alias("raw_low"), + ]) + if "_adj_factor" in df.columns: + af = pl.col("_adj_factor").fill_null(1.0) + df = df.with_columns([ + (pl.col("open") * af).alias("open"), + (pl.col("high") * af).alias("high"), + (pl.col("low") * af).alias("low"), + (pl.col("close") * af).alias("close"), + ]) + + # ---- volume 统一 Float64 ---- + df = df.with_columns(pl.col("volume").cast(pl.Float64)) + + # ---- ex_rights: 盘中除权极罕见, 直接 false ---- + df = df.with_columns(pl.lit(False).alias("ex_rights")) + + # ---- 基础涨跌 ---- + # prev_close: 有则直接用 (来自 API quote_extra, raw), 需要乘 adj_factor 对齐复权价 + if "prev_close" not in df.columns: + prev_close = pl.col("close_right") if "close_right" in df.columns else pl.col("close") + df = df.with_columns(prev_close.alias("prev_close")) + elif "_adj_factor" in df.columns: + # 保存 API 原始前收盘价 (用于涨跌停价计算) + df = df.with_columns(pl.col("prev_close").alias("_prev_close_raw")) + # API 返回的 prev_close 是原始价, 乘复权因子对齐复权价 (用于 change_pct) + df = df.with_columns((pl.col("prev_close") * pl.col("_adj_factor").fill_null(1.0)).alias("prev_close")) + + # change_pct / change_amount / amplitude: 有则直接用, 无则计算 + if "change_pct" not in df.columns: + df = df.with_columns((pl.col("close") / pl.col("prev_close") - 1).alias("change_pct")) + if "change_amount" not in df.columns: + df = df.with_columns((pl.col("close") - pl.col("prev_close")).alias("change_amount")) + if "amplitude" not in df.columns: + df = df.with_columns( + pl.when(pl.col("prev_close") > 0) + .then((pl.col("high") - pl.col("low")) / pl.col("prev_close")) + .otherwise(None) + .alias("amplitude"), + ) + + # ---- EMA (递推) ---- + df = df.with_columns([ + (alpha(5) * pl.col("close") + (1 - alpha(5)) * pl.col("ema5")).alias("ema5"), + (alpha(10) * pl.col("close") + (1 - alpha(10)) * pl.col("ema10")).alias("ema10"), + (alpha(20) * pl.col("close") + (1 - alpha(20)) * pl.col("ema20")).alias("ema20"), + (alpha(30) * pl.col("close") + (1 - alpha(30)) * pl.col("ema30")).alias("ema30"), + (alpha(60) * pl.col("close") + (1 - alpha(60)) * pl.col("ema60")).alias("ema60"), + ]) + + # ---- MACD (递推) ---- + ema12 = alpha(12) * pl.col("close") + (1 - alpha(12)) * pl.col("_ema12") + ema26 = alpha(26) * pl.col("close") + (1 - alpha(26)) * pl.col("_ema26") + dif = ema12 - ema26 + dea = alpha(9) * dif + (1 - alpha(9)) * pl.col("macd_dea") + df = df.with_columns([ + dif.alias("macd_dif"), + dea.alias("macd_dea"), + ((dif - dea) * 2).alias("macd_hist"), + ]) + + # ---- MA (用部分和) ---- + df = df.with_columns([ + ((pl.col("_ma5_partial_sum") + pl.col("close")) / 5).alias("ma5"), + ((pl.col("_ma10_partial_sum") + pl.col("close")) / 10).alias("ma10"), + ((pl.col("_ma20_partial_sum") + pl.col("close")) / 20).alias("ma20"), + ((pl.col("_ma30_partial_sum") + pl.col("close")) / 30).alias("ma30"), + ((pl.col("_ma60_partial_sum") + pl.col("close")) / 60).alias("ma60"), + ]) + + # ---- Bollinger ---- + boll_sum = pl.col("_boll_partial_sum") + pl.col("close") + boll_sq_sum = pl.col("_boll_partial_sq_sum") + pl.col("close") ** 2 + boll_ma = boll_sum / 20 + boll_var = boll_sq_sum / 20 - boll_ma ** 2 + boll_std = pl.when(boll_var > 0).then(boll_var.sqrt()).otherwise(0.0) + df = df.with_columns([ + (boll_ma + 2 * boll_std).alias("boll_upper"), + (boll_ma - 2 * boll_std).alias("boll_lower"), + ]) + + # ---- KDJ (递推) ---- + kdj_ln = pl.min_horizontal(pl.col("_kdj_8d_low"), pl.col("low")) + kdj_hn = pl.max_horizontal(pl.col("_kdj_8d_high"), pl.col("high")) + rsv = (pl.col("close") - kdj_ln) / (kdj_hn - kdj_ln).fill_null(1e-12) * 100 + k_today = rsv / 3 + pl.col("kdj_k") * 2 / 3 + d_today = k_today / 3 + pl.col("kdj_d") * 2 / 3 + df = df.with_columns([ + k_today.alias("kdj_k"), + d_today.alias("kdj_d"), + (3 * k_today - 2 * d_today).alias("kdj_j"), + ]) + + # ---- ATR (递推) ---- + tr = pl.max_horizontal( + pl.col("high") - pl.col("low"), + (pl.col("high") - pl.col("prev_close")).abs(), + (pl.col("low") - pl.col("prev_close")).abs(), + ) + df = df.with_columns( + (tr / 14 + pl.col("atr_14") * 13 / 14).alias("atr_14"), + ) + + # ---- RSI (递推, n=6,14,24) ---- + delta = pl.col("close") - pl.col("prev_close") + gain = pl.when(delta > 0).then(delta).otherwise(0.0) + loss = pl.when(delta < 0).then(-delta).otherwise(0.0) + for n in (6, 14, 24): + a = 1.0 / n + avg_gain = (1 - a) * pl.col(f"_rsi_avg_gain_{n}") + a * gain + avg_loss = (1 - a) * pl.col(f"_rsi_avg_loss_{n}") + a * loss + df = df.with_columns([ + avg_gain.alias(f"_rsi_avg_gain_{n}"), + avg_loss.alias(f"_rsi_avg_loss_{n}"), + (100 - 100 / (1 + avg_gain / pl.when(avg_loss == 0).then(1e-12).otherwise(avg_loss))) + .alias(f"rsi_{n}"), + ]) + + # ---- 量比 ---- + vol_ma5 = (pl.col("_vol_ma5_partial_sum") + pl.col("volume")) / 5 + vol_ma10 = (pl.col("_vol_ma10_partial_sum") + pl.col("volume")) / 10 + df = df.with_columns([ + vol_ma5.alias("vol_ma5"), + vol_ma10.alias("vol_ma10"), + (pl.col("volume") / vol_ma5).alias("vol_ratio_5d"), + ]) + + # ---- 极值 60 日 ---- + df = df.with_columns([ + pl.max_horizontal(pl.col("_high_59d"), pl.col("high")).alias("high_60d"), + pl.min_horizontal(pl.col("_low_59d"), pl.col("low")).alias("low_60d"), + ]) + + # ---- 动量 (5d/10d/20d/30d/60d) ---- + df = df.with_columns([ + (pl.col("close") / pl.col("_close_5d_ago") - 1).alias("momentum_5d"), + (pl.col("close") / pl.col("_close_10d_ago") - 1).alias("momentum_10d"), + (pl.col("close") / pl.col("_close_20d_ago") - 1).alias("momentum_20d"), + (pl.col("close") / pl.col("_close_30d_ago") - 1).alias("momentum_30d"), + (pl.col("close") / pl.col("_close_60d_ago") - 1).alias("momentum_60d"), + ]) + + # ---- 年化波动率 20d (递推) ---- + # 用 Welford 简化: sum + sum_sq of 19 historical returns + today's return + today_ret = pl.col("close") / pl.col("prev_close") - 1 + total_sum = pl.col("_vol_19d_pct_sum").fill_null(0.0) + today_ret + total_sq_sum = pl.col("_vol_19d_pct_sq_sum").fill_null(0.0) + today_ret ** 2 + vol_mean = total_sum / 20 + vol_var = total_sq_sum / 20 - vol_mean ** 2 + df = df.with_columns( + pl.when(vol_var > 0) + .then(vol_var.sqrt() * (252 ** 0.5)) + .otherwise(None) + .alias("annual_vol_20d"), + ) + + # ---- 信号 (需要昨天的指标值判断交叉) ---- + if not prev_enriched.is_empty(): + sig_prev = prev_enriched.select( + "symbol", + pl.col("ma5").alias("_prev_ma5"), + pl.col("ma20").alias("_prev_ma20"), + pl.col("ma60").alias("_prev_ma60"), + pl.col("macd_dif").alias("_prev_dif"), + pl.col("macd_dea").alias("_prev_dea"), + pl.col("boll_upper").alias("_prev_boll_upper"), + pl.col("boll_lower").alias("_prev_boll_lower"), + pl.col("close").alias("_prev_close_enriched"), + ) + df = df.join(sig_prev, on="symbol", how="left") + + df = df.with_columns([ + # MA 金叉/死叉 + ((pl.col("ma5") > pl.col("ma20")) & (pl.col("_prev_ma5") <= pl.col("_prev_ma20"))) + .alias("signal_ma_golden_5_20"), + ((pl.col("ma5") < pl.col("ma20")) & (pl.col("_prev_ma5") >= pl.col("_prev_ma20"))) + .alias("signal_ma_dead_5_20"), + ((pl.col("ma20") > pl.col("ma60")) & (pl.col("_prev_ma20") <= pl.col("_prev_ma60"))) + .alias("signal_ma_golden_20_60"), + # MACD 金叉/死叉 + ((pl.col("macd_dif") > pl.col("macd_dea")) & (pl.col("_prev_dif") <= pl.col("_prev_dea"))) + .alias("signal_macd_golden"), + ((pl.col("macd_dif") < pl.col("macd_dea")) & (pl.col("_prev_dif") >= pl.col("_prev_dea"))) + .alias("signal_macd_dead"), + # MA20 突破/跌破 + ((pl.col("close") > pl.col("ma20")) & (pl.col("_prev_close_enriched") <= pl.col("_prev_ma20"))) + .alias("signal_ma20_breakout"), + ((pl.col("close") < pl.col("ma20")) & (pl.col("_prev_close_enriched") >= pl.col("_prev_ma20"))) + .alias("signal_ma20_breakdown"), + # BOLL 突破 + (pl.col("close") >= pl.col("boll_upper")).alias("signal_boll_breakout_upper"), + (pl.col("close") <= pl.col("boll_lower")).alias("signal_boll_breakdown_lower"), + ]) + + df = df.drop([ + c for c in df.columns + if c.startswith("_prev_") and c not in {"_prev_consec_up", "_prev_consec_down"} + ]) + + # N日新高/新低 + 放量 + df = df.with_columns([ + (pl.col("close") >= pl.col("high_60d")).alias("signal_n_day_high"), + (pl.col("close") <= pl.col("low_60d")).alias("signal_n_day_low"), + (pl.col("vol_ratio_5d") >= 2.0).alias("signal_volume_surge"), + ]) + + # ---- 涨跌停 + 换手率 + 炸板 + 连板 ---- + if instruments is not None and not instruments.is_empty(): + df = _compute_limit_signals_today(df, instruments) + + # ---- 清理内部列 ---- + drop_cols = [ + "close_right", "high_right", "low_right", "_prev_close_raw", + "_ma5_partial_sum", "_ma10_partial_sum", "_ma20_partial_sum", + "_ma30_partial_sum", "_ma60_partial_sum", + "_boll_partial_sum", "_boll_partial_sq_sum", + "_high_59d", "_low_59d", + "_close_5d_ago", "_close_10d_ago", "_close_20d_ago", + "_close_30d_ago", "_close_60d_ago", + "_vol_ma5_partial_sum", "_vol_ma10_partial_sum", + "_kdj_8d_low", "_kdj_8d_high", + "_window_len", + "_rsi_avg_gain_6", "_rsi_avg_loss_6", + "_rsi_avg_gain_14", "_rsi_avg_loss_14", + "_rsi_avg_gain_24", "_rsi_avg_loss_24", + "_ema12", "_ema26", + "_adj_factor", + "_vol_19d_pct_sum", "_vol_19d_pct_sq_sum", + "_prev_consec_up", "_prev_consec_down", + ] + df = df.drop([c for c in drop_cols if c in df.columns]) + + # 自定义信号(日级实时路径同样注入) + from app.strategy import custom_signals + df = custom_signals.inject(df, _get_custom_signal_exprs()) + + # 清理 NaN / Inf + float_cols = [c for c in df.columns if df[c].dtype.is_float()] + if float_cols: + df = df.with_columns([ + pl.when(pl.col(c).is_nan() | pl.col(c).is_infinite()) + .then(None) + .otherwise(pl.col(c)) + .alias(c) + for c in float_cols + ]) + + return df + + +def _compute_limit_signals_today(df: pl.DataFrame, instruments: pl.DataFrame) -> pl.DataFrame: + """盘中增量版的涨跌停/换手率/炸板/连板计算。""" + inst_cols = ["symbol"] + if "float_shares" in instruments.columns: + inst_cols.append("float_shares") + inst_subset = instruments.select(inst_cols).unique(subset=["symbol"]) + if "name" in instruments.columns: + st_flag = ( + instruments + .select("symbol", pl.col("name").str.contains("ST").alias("_is_st")) + .unique(subset=["symbol"]) + ) + inst_subset = inst_subset.join(st_flag, on="symbol", how="left") + + df = df.join(inst_subset, on="symbol", how="left", suffix="_inst") + + # 换手率: API 有则直接用, 无则从 float_shares 计算 + if "turnover_rate" not in df.columns: + if "float_shares" in df.columns and "volume" in df.columns: + df = df.with_columns( + pl.when(pl.col("float_shares") > 0) + .then(pl.col("volume") * 10000.0 / pl.col("float_shares")) + .otherwise(None) + .alias("turnover_rate") + ) + + # 涨跌停 (用 raw_close / raw_high 和前一日原始收盘价) + # 优先用 API 原始前收盘价, 回退到 close_right, 最后回退到 raw_close + if "_prev_close_raw" in df.columns: + if "close_right" in df.columns: + prev_raw = pl.when(pl.col("_prev_close_raw").is_not_null()).then(pl.col("_prev_close_raw")).otherwise(pl.col("close_right")) + else: + prev_raw = pl.col("_prev_close_raw") + elif "close_right" in df.columns: + prev_raw = pl.col("close_right") + else: + prev_raw = pl.col("raw_close") + is_chinext = pl.col("symbol").str.starts_with("300") | pl.col("symbol").str.starts_with("301") + is_star = pl.col("symbol").str.starts_with("688") | pl.col("symbol").str.starts_with("689") + is_bj = pl.col("symbol").str.ends_with(".BJ") + limit_pct = ( + pl.when(is_chinext).then(0.20) + .when(is_star).then(0.20) + .when(is_bj).then(0.30) + .otherwise(0.10) + ) + if "_is_st" in df.columns: + limit_pct = pl.when(pl.col("_is_st").fill_null(False)).then(0.05).otherwise(limit_pct) + limit_pct = limit_pct.alias("_limit_pct") + + limit_up_price = _limit_price(prev_raw, limit_pct, up=True) + limit_down_price = _limit_price(prev_raw, limit_pct, up=False) + + is_limit_up = ( + pl.when((prev_raw > 0) & (pl.col("raw_close") > 0)) + .then((pl.col("raw_close") - limit_up_price).abs() < 0.005) + .otherwise(None).cast(pl.Boolean) + ) + is_limit_down = ( + pl.when((prev_raw > 0) & (pl.col("raw_close") > 0)) + .then((pl.col("raw_close") - limit_down_price).abs() < 0.005) + .otherwise(None).cast(pl.Boolean) + ) + + df = df.with_columns([ + is_limit_up.alias("signal_limit_up"), + is_limit_down.alias("signal_limit_down"), + # 跌停翘板 + pl.when(prev_raw > 0) + .then( + (~is_limit_down.fill_null(True)) + & (pl.col("low") <= limit_down_price + 0.005) + & (pl.col("close") > pl.col("open")) + ).otherwise(None).cast(pl.Boolean) + .alias("signal_limit_down_recovery"), + # 炸板: 最高价曾触及涨停价 + 最终未封住 + pl.when((prev_raw > 0) & (pl.col("raw_high") > 0)) + .then( + (~is_limit_up.fill_null(True)) + & (pl.col("raw_high") >= limit_up_price - 0.005) + ).otherwise(None).cast(pl.Boolean) + .alias("signal_broken_limit_up"), + ]) + + # 连板数: 同向 +1, 不同向归零 + # _prev_consec_up / _prev_consec_down 来自 live_agg (昨日 enriched) + if "_prev_consec_up" not in df.columns: + df = df.with_columns(pl.lit(0).cast(pl.UInt32).alias("_prev_consec_up")) + if "_prev_consec_down" not in df.columns: + df = df.with_columns(pl.lit(0).cast(pl.UInt32).alias("_prev_consec_down")) + prev_up = pl.col("_prev_consec_up").fill_null(0).cast(pl.UInt32) + prev_down = pl.col("_prev_consec_down").fill_null(0).cast(pl.UInt32) + df = df.with_columns([ + pl.when(is_limit_up.fill_null(False)) + .then((prev_up + 1).cast(pl.UInt32)) + .otherwise(pl.lit(0).cast(pl.UInt32)) + .alias("consecutive_limit_ups"), + pl.when(is_limit_down.fill_null(False)) + .then((prev_down + 1).cast(pl.UInt32)) + .otherwise(pl.lit(0).cast(pl.UInt32)) + .alias("consecutive_limit_downs"), + ]) + + # 清理 + cleanup = ["_limit_pct", "_is_st"] + for c in df.columns: + if c.endswith("_inst"): + cleanup.append(c) + for c in ["name", "float_shares"]: + if c in df.columns: + cleanup.append(c) + df = df.drop([c for c in cleanup if c in df.columns]) + + return df diff --git a/backend/app/jobs/__init__.py b/backend/app/jobs/__init__.py new file mode 100644 index 0000000..3daa442 --- /dev/null +++ b/backend/app/jobs/__init__.py @@ -0,0 +1 @@ +"""APScheduler 任务。""" diff --git a/backend/app/jobs/daily_pipeline.py b/backend/app/jobs/daily_pipeline.py new file mode 100644 index 0000000..fe8c13c --- /dev/null +++ b/backend/app/jobs/daily_pipeline.py @@ -0,0 +1,499 @@ +"""盘后管道 + 盘前维表同步。 + +调度: + 09:10 盘前 — 同步标的维表 instruments (全量覆盖) + 15:30 盘后 — 日K同步 + 增量除权因子 + enriched 计算 + 刷新视图 + +盘后同步策略: + 日 K: QuoteService 交易时段已实时落盘 → 有数据时跳过 batch,首次拉 1 年区间 + 除权因子: 从已有数据最新日期的下一天开始增量获取,避免重复拉取和计算 +""" +from __future__ import annotations + +import logging +from collections.abc import Callable +from pathlib import Path + +import polars as pl +from apscheduler.schedulers.asyncio import AsyncIOScheduler +from apscheduler.triggers.cron import CronTrigger + +from app.indicators.pipeline import run_pipeline +from app.config import settings +from app.services import index_sync, instrument_sync, kline_sync +from app.tickflow.capabilities import Cap, CapabilitySet +from app.tickflow.pools import DEMO_SYMBOLS, get_pool +from app.tickflow.repository import KlineRepository + +logger = logging.getLogger(__name__) + +ProgressCb = Callable[..., None] + + +def _noop(stage: str, pct: int, msg: str, **kwargs) -> None: # noqa: ARG001 + pass + + +def _invalidate(table: str | None = None) -> None: + """stage 写完调用,让 /api/data/status 只重算被影响的那张表。""" + from app.api.data import invalidate_data_cache + invalidate_data_cache(table) + + +def _resolve_universe(capset: CapabilitySet) -> list[str]: + """解析标的池 — 以 CN_Equity_A (沪深京A股 ~5522只) 为主。 + + 有 batch 能力 → 直接拉 CN_Equity_A universe + 其他用户 → 用 instruments parquet + watchlist 兜底 + """ + if capset.has(Cap.KLINE_DAILY_BATCH): + try: + all_a = get_pool("CN_Equity_A", refresh=True) + if all_a: + return sorted(all_a) + except Exception as e: # noqa: BLE001 + logger.warning("CN_Equity_A pool unavailable, fallback: %s", e) + + # Free 用户兜底: instruments parquet + watchlist + demo + base: set[str] = set(DEMO_SYMBOLS) + base.update(get_pool("watchlist")) + d = Path(settings.data_dir) + inst_path = d / "instruments" / "instruments.parquet" + if inst_path.exists(): + try: + inst = pl.read_parquet(inst_path, columns=["symbol"]) + base.update(inst["symbol"].to_list()) + except Exception as e: # noqa: BLE001 + logger.warning("instruments supplement failed: %s", e) + return sorted(base) + + +def run_instruments_sync(repo: KlineRepository) -> dict: + """盘前同步标的维表。""" + rows = instrument_sync.sync_instruments(repo.store.data_dir) + _refresh_instruments_view(repo) + _invalidate("instruments") + return {"instruments_rows": rows} + + +def run_now( + repo: KlineRepository, + capset: CapabilitySet, + on_progress: ProgressCb | None = None, +) -> dict: + """立即执行一次盘后管道,支持进度回调。 + + 跳过的 stage **不 emit**,避免前端把"无 capability"的卡片错误标记为 active/done。 + result 里带 skipped_stages 列表供前端展示。 + """ + emit = on_progress or _noop + skipped: list[str] = [] + + # Step 0: 先同步标的维表, 再解析标的池 — 确保标的池基于最新 instruments + emit("sync_instruments", 2, "同步标的维表…") + inst_rows = instrument_sync.sync_instruments(repo.store.data_dir) + if inst_rows > 0: + _refresh_instruments_view(repo) + emit("sync_instruments", 8, f"标的维表同步完成,{inst_rows} 只标的") + _invalidate("instruments") + + emit("resolve_universe", 9, "解析标的池…") + universe = _resolve_universe(capset) + emit("resolve_universe", 10, f"标的池规模:{len(universe)} 只") + + # Step 1: 日 K 同步 + # 今天有数据 → 实时行情接口拉一次覆写(1请求全市场) + # 今天没数据 → batch K-line API 补齐 + # 无任何数据 → batch K-line API 拉首次 1 年 + from datetime import date as _date, timedelta as _td, datetime as _dt + latest_daily = repo.latest_daily_date() + today = _date.today() + today_exists = latest_daily and latest_daily >= today + new_daily_days = 0 + + if today_exists: + # 今天有数据(QuoteService 已落盘)→ 实时行情覆写,确保最新 + emit("sync_daily", 12, f"获取日K [{today} ~ {today}] 实时行情…") + written_daily = kline_sync.sync_daily_by_quotes(repo) + new_daily_days = 1 + emit("sync_daily", 45, f"日K 完成,{written_daily} 只标的") + logger.info("sync_daily: [%s ~ %s] live quotes, %d symbols", today, today, written_daily) + elif latest_daily: + # 有历史但今天没数据 → batch 补齐缺口 + start_date = latest_daily + emit("sync_daily", 12, f"获取日K [{start_date} ~ {today}]…") + logger.info("sync_daily: [%s ~ %s] gap fill", start_date, today) + + def _daily_chunk_progress(cur: int, tot: int) -> None: + emit("sync_daily", 12 + int(33 * cur / tot), + f"日K 批次 {cur}/{tot}", stage_pct=int(100 * cur / tot), skip_log=True) + written_daily = kline_sync.sync_and_persist_daily_batch( + universe, repo, capset, + start_date=_dt.combine(start_date, _dt.min.time()), + end_date=_dt.combine(today, _dt.min.time()), + on_chunk_done=_daily_chunk_progress, + ) + gap_days = (today - start_date).days + new_daily_days = gap_days + emit("sync_daily", 45, f"日K 完成,覆盖 {gap_days} 天") + logger.info("sync_daily: [%s ~ %s] done, %d days", start_date, today, gap_days) + else: + # 首次:无任何数据 → batch 拉 1 年 + start_date = today - _td(days=365) + emit("sync_daily", 12, f"获取日K [{start_date} ~ {today}]…") + logger.info("sync_daily: [%s ~ %s] initial fetch", start_date, today) + + def _daily_chunk_progress(cur: int, tot: int) -> None: + emit("sync_daily", 12 + int(33 * cur / tot), + f"日K 批次 {cur}/{tot}", stage_pct=int(100 * cur / tot), skip_log=True) + written_daily = kline_sync.sync_and_persist_daily_batch( + universe, repo, capset, + start_date=_dt.combine(start_date, _dt.min.time()), + end_date=_dt.combine(today, _dt.min.time()), + on_chunk_done=_daily_chunk_progress, + ) + new_daily_days = 365 + emit("sync_daily", 45, "日K 完成") + logger.info("sync_daily: [%s ~ %s] done", start_date, today) + _invalidate("daily") + + # Step 1.5: 增量同步除权因子 — 从已有数据最新日期的下一天开始获取 + written_adj = 0 + affected_symbols: list[str] = [] + if capset.has(Cap.ADJ_FACTOR): + from datetime import datetime, timedelta + adj_end = datetime.now() + # 从已有除权因子数据的最新日期开始获取,避免重复拉取 + adj_factor_path = repo.store.data_dir / "adj_factor" / "all.parquet" + fallback_start = adj_end - timedelta(days=30) + if adj_factor_path.exists(): + try: + from datetime import date as date_cls + max_date = pl.scan_parquet(adj_factor_path).select( + pl.col("trade_date").max() + ).collect().item() + if max_date is not None: + # trade_date 可能是 date / datetime / string 类型 + if isinstance(max_date, str): + td = date_cls.fromisoformat(max_date) + elif isinstance(max_date, datetime): + td = max_date.date() + else: + td = max_date + adj_start = datetime.combine(td, datetime.min.time()) + else: + adj_start = fallback_start + except Exception: + adj_start = fallback_start + else: + adj_start = fallback_start + adj_start_str = adj_start.strftime("%Y-%m-%d") + adj_end_str = adj_end.strftime("%Y-%m-%d") + emit("sync_adj", 50, f"获取除权因子 [{adj_start_str} ~ {adj_end_str}]…") + logger.info("sync_adj: [%s ~ %s] start", adj_start_str, adj_end_str) + + def _adj_chunk_progress(cur: int, tot: int) -> None: + emit("sync_adj", 50 + int(10 * cur / tot), + f"除权因子批次 {cur}/{tot}", stage_pct=int(100 * cur / tot), skip_log=True) + written_adj, affected_symbols = kline_sync.sync_adj_factor( + universe, repo, capset, + start_time=adj_start, end_time=adj_end, + on_chunk_done=_adj_chunk_progress, + ) + if affected_symbols: + _refresh_single_view(repo, "adj_factor") + emit("sync_adj", 60, f"除权因子完成,新增 {len(affected_symbols)} 只个股") + logger.info("sync_adj: [%s ~ %s] done, %d symbols", adj_start_str, adj_end_str, len(affected_symbols)) + else: + emit("sync_adj", 60, "除权因子完成,无新增") + logger.info("sync_adj: [%s ~ %s] no new factors", adj_start_str, adj_end_str) + _invalidate("adj_factor") + else: + skipped.append("sync_adj") + logger.info("sync_adj skipped: no ADJ_FACTOR capability") + + # Step 2: 计算 enriched + # 判断策略: + # - 首次 (enriched 目录不存在) → 全量 + # - 往前扩展历史 (新日期 < enriched 已有最早日期) → 全量 + # 前面的除权因子会改变累积因子链,影响后面所有日期的复权价格 + # - 往后新增日期 (新日期 > enriched 已有最晚日期) + # → 增量补新区块(所有标的) + 受除权影响个股全日期重算 + # - 无新日期 + 有新除权因子 → 增量: 只重算受影响个股的全部日期 + # - 无新日期 + 无变化 → 跳过 + enriched_dir = repo.store.data_dir / "kline_daily_enriched" + enriched_exists = enriched_dir.exists() and any(enriched_dir.glob("date=*")) + daily_dir = repo.store.data_dir / "kline_daily" + daily_days = len(list(daily_dir.glob("date=*"))) if daily_dir.exists() else 0 + prev_enriched_days = len(list(enriched_dir.glob("date=*"))) if enriched_exists else 0 + + # 判断新日期方向: 找 daily 和 enriched 的日期集合做比较 + forward_incremental = False + backward_extension = False + + if daily_days > prev_enriched_days and enriched_exists: + daily_dates = sorted(d.stem.split("=")[1] for d in daily_dir.glob("date=*")) + enriched_dates = sorted(d.stem.split("=")[1] for d in enriched_dir.glob("date=*")) + earliest_enriched = enriched_dates[0] + latest_enriched = enriched_dates[-1] + new_dates = set(daily_dates) - set(enriched_dates) + if new_dates: + # 有新日期早于 enriched 最早日期 → 往前扩展 + if any(d < earliest_enriched for d in new_dates): + backward_extension = True + # 有新日期晚于 enriched 最晚日期 → 往后新增 + if any(d > latest_enriched for d in new_dates): + forward_incremental = True + + def _enriched_batch_progress(cur: int, tot: int) -> None: + emit("compute_enriched", 65 + int(23 * cur / tot), + f"计算指标 批次 {cur}/{tot}", stage_pct=int(100 * cur / tot), skip_log=True) + + if not enriched_exists or backward_extension: + # 首次 或 往前扩展 → 全量 + emit("compute_enriched", 65, "全量计算 enriched…") + logger.info("compute_enriched: full rebuild (first=%s, backward=%s, daily=%d, enriched=%d)", + not enriched_exists, backward_extension, daily_days, prev_enriched_days) + written_enriched = run_pipeline(on_batch_done=_enriched_batch_progress) + new_enriched_days = len(list(enriched_dir.glob("date=*"))) + emit("compute_enriched", 88, f"enriched 完成,覆盖 {new_enriched_days} 天") + logger.info("compute_enriched: full rebuild done, %d days", new_enriched_days) + elif forward_incremental: + # 往后新增日期: 增量补新区块 + 受影响个股全日期重算 + symbols_to_recompute = list(set(affected_symbols)) if affected_symbols else [] + emit("compute_enriched", 65, + f"增量计算 enriched (新日期 + {len(symbols_to_recompute)} 只个股重算)…" + if symbols_to_recompute else "增量计算 enriched (新日期)…") + logger.info("compute_enriched: forward incremental, %d symbols to recompute", + len(symbols_to_recompute)) + written_enriched = run_pipeline( + new_dates_only=True, + symbols=symbols_to_recompute or None, + on_batch_done=_enriched_batch_progress, + ) + new_enriched_days = len(list(enriched_dir.glob("date=*"))) + emit("compute_enriched", 88, f"enriched 完成,覆盖 {new_enriched_days} 天") + logger.info("compute_enriched: forward incremental done, %d days", new_enriched_days) + elif affected_symbols: + # 无新日期,仅除权因子变更 → 只重算受影响个股的全部日期 + emit("compute_enriched", 65, f"增量计算 enriched ({len(affected_symbols)} 只个股)…") + logger.info("compute_enriched: adj_factor incremental, %d symbols", len(affected_symbols)) + written_enriched = run_pipeline(symbols=affected_symbols, on_batch_done=_enriched_batch_progress) + emit("compute_enriched", 88, f"enriched 完成,{len(affected_symbols)} 只个股") + else: + written_enriched = 0 + logger.info("compute_enriched: skip (no new daily, no adj_factor changes)") + _refresh_single_view(repo, "kline_enriched") + _invalidate("enriched") + + # Step 2.3: 指数同步 — 独立 kline_index_* 存储,不进入股票选股/策略链路。 + written_index_daily = 0 + index_count = 0 + if capset.has(Cap.KLINE_DAILY_BATCH): + emit("sync_index", 88, "同步指数列表与日K…") + try: + index_count = index_sync.sync_index_instruments(repo) + index_dir = repo.store.data_dir / "kline_index_enriched" + index_dates = sorted( + d.name[5:] for d in index_dir.glob("date=*") + if d.is_dir() and d.name.startswith("date=") + ) if index_dir.exists() else [] + index_start = _date.fromisoformat(index_dates[-1]) if index_dates else today - _td(days=365) + written_index_daily = index_sync.sync_and_persist_index_daily( + repo, + capset, + start_date=_dt.combine(index_start, _dt.min.time()), + end_date=_dt.combine(today, _dt.min.time()), + ) + repo.refresh_index_views() + _invalidate("index_instruments") + _invalidate("index_daily") + _invalidate("index_enriched") + emit("sync_index", 89, f"指数完成,{index_count} 只指数,{written_index_daily} 行日K") + except Exception as e: # noqa: BLE001 + logger.warning("sync_index failed: %s", e) + emit("sync_index", 89, f"指数同步失败:{e}") + else: + skipped.append("sync_index") + + # Step 2.5: 分钟 K 同步(可选) — 未启用或无 capability 时静默跳过(不 emit) + from app.services import preferences + minute_on = preferences.get_minute_sync_enabled() + minute_days = preferences.get_minute_sync_days() + written_minute = 0 + if minute_on and capset.has(Cap.KLINE_MINUTE_BATCH): + minute_start = today - _td(days=minute_days) + emit("sync_minute", 90, f"获取分钟K [{minute_start} ~ {today}]…") + logger.info("sync_minute: [%s ~ %s] start", minute_start, today) + minute_symbols = _resolve_minute_symbols(capset) + def _minute_chunk_progress(cur: int, tot: int) -> None: + emit("sync_minute", 90 + int(3 * cur / tot), + f"分钟K 批次 {cur}/{tot}", stage_pct=int(100 * cur / tot), skip_log=True) + written_minute = kline_sync.sync_and_persist_minute( + minute_symbols, repo, capset, days=minute_days, + on_chunk_done=_minute_chunk_progress, + ) + minute_dir = repo.store.data_dir / "kline_minute" + minute_cover_days = len(list(minute_dir.glob("date=*"))) if minute_dir.exists() else 0 + emit("sync_minute", 93, f"分钟K完成,覆盖 {minute_cover_days} 天") + logger.info("sync_minute: [%s ~ %s] done, %d days", minute_start, today, minute_cover_days) + _invalidate("minute") + else: + skipped.append("sync_minute") + if minute_on: + logger.info("sync_minute skipped: no KLINE_MINUTE_BATCH capability") + else: + logger.info("sync_minute skipped: user disabled") + + # Step 3: 刷新视图 + emit("refresh_views", 95, "刷新 DuckDB 视图…") + _refresh_views(repo) + + emit("done", 100, "完成") + _invalidate(None) # 兜底:全清 + + return { + "universe_size": len(universe), + "daily_days": new_daily_days, + "adj_factor_symbols": len(affected_symbols), + "enriched_days": written_enriched, + "index_count": index_count, + "index_daily_rows": written_index_daily, + "minute_rows": written_minute, + "skipped_stages": skipped, + } + + +def _refresh_views(repo: KlineRepository) -> None: + """刷新所有 DuckDB 视图。""" + d = repo.store.data_dir.as_posix() + views = { + "kline_daily": f"{d}/kline_daily/**/*.parquet", + "kline_enriched": f"{d}/kline_daily_enriched/**/*.parquet", + "kline_index_daily": f"{d}/kline_index_daily/**/*.parquet", + "kline_index_enriched": f"{d}/kline_index_enriched/**/*.parquet", + "kline_minute": f"{d}/kline_minute/**/*.parquet", + "adj_factor": f"{d}/adj_factor/**/*.parquet", + "instruments": f"{d}/instruments/**/*.parquet", + "instruments_index": f"{d}/instruments_index/**/*.parquet", + } + for name, path in views.items(): + try: + repo.db.execute( + f"CREATE OR REPLACE VIEW {name} AS " + f"SELECT * FROM read_parquet('{path}', union_by_name=true)" + ) + except Exception as e: # noqa: BLE001 + logger.warning("refresh view %s failed: %s", name, e) + + +def _refresh_single_view(repo: KlineRepository, name: str) -> None: + """刷新单个 DuckDB 视图。""" + d = repo.store.data_dir.as_posix() + paths = { + "kline_daily": f"{d}/kline_daily/**/*.parquet", + "kline_enriched": f"{d}/kline_daily_enriched/**/*.parquet", + "kline_index_daily": f"{d}/kline_index_daily/**/*.parquet", + "kline_index_enriched": f"{d}/kline_index_enriched/**/*.parquet", + "kline_minute": f"{d}/kline_minute/**/*.parquet", + "adj_factor": f"{d}/adj_factor/**/*.parquet", + "instruments": f"{d}/instruments/**/*.parquet", + "instruments_index": f"{d}/instruments_index/**/*.parquet", + } + path = paths.get(name) + if not path: + return + try: + repo.db.execute( + f"CREATE OR REPLACE VIEW {name} AS " + f"SELECT * FROM read_parquet('{path}', union_by_name=true)" + ) + except Exception as e: # noqa: BLE001 + logger.warning("refresh view %s failed: %s", name, e) + + +def _resolve_minute_symbols(capset: CapabilitySet) -> list[str]: + """分钟 K 同步标的 — 与日K共用同一标的池。""" + return _resolve_universe(capset) + + +def _refresh_instruments_view(repo: KlineRepository) -> None: + """单独刷新 instruments 视图。""" + d = repo.store.data_dir.as_posix() + try: + repo.db.execute( + f"CREATE OR REPLACE VIEW instruments AS " + f"SELECT * FROM read_parquet('{d}/instruments/**/*.parquet', union_by_name=true)" + ) + except Exception as e: # noqa: BLE001 + logger.warning("refresh instruments view failed: %s", e) + + +def _run_tracked(fn, job_label: str) -> None: + """调度触发时包装 JobStore 跟踪,确保同步历史有记录。""" + from app.services.pipeline_jobs import job_store + + job_id = job_store.create() + job_store.start(job_id) + + def progress(stage: str, pct: int, msg: str, stage_pct: int | None = None, + skip_log: bool = False) -> None: + job_store.progress(job_id, stage, pct, msg, stage_pct=stage_pct, skip_log=skip_log) + + try: + result = fn(on_progress=progress) + job_store.succeed(job_id, result) + logger.info("scheduled %s completed: job_id=%s", job_label, job_id) + except Exception: + logger.exception("scheduled %s failed: job_id=%s", job_label, job_id) + job_store.fail(job_id, f"scheduled {job_label} failed") + + +def start_scheduler(repo: KlineRepository, capset: CapabilitySet) -> AsyncIOScheduler: + """启动调度器。 + + 工作日 09:10 — 同步标的维表 + 工作日 HH:MM — 盘后管道(时间由用户偏好决定,默认 15:30) + """ + from app.services import preferences + sched = preferences.get_pipeline_schedule() + inst_sched = preferences.get_instruments_schedule() + + scheduler = AsyncIOScheduler(timezone="Asia/Shanghai") + + # 盘前: 同步 instruments(时间由偏好决定) + def _instruments_task(on_progress=None): + emit = on_progress or _noop + emit("sync_instruments", 0, "同步标的维表…") + result = run_instruments_sync(repo) + emit("done", 100, f"标的维表同步完成,{result.get('instruments_rows', 0)} 只标的") + return result + + scheduler.add_job( + lambda: _run_tracked(_instruments_task, "instruments_sync"), + trigger=CronTrigger(day_of_week="mon-fri", + hour=inst_sched["hour"], minute=inst_sched["minute"], + timezone="Asia/Shanghai"), + id="pre_market_instruments", + misfire_grace_time=1800, + replace_existing=True, + ) + + # 盘后: 日 K + enriched(时间由偏好决定) + scheduler.add_job( + lambda: _run_tracked( + lambda on_progress=None: run_now(repo, capset, on_progress=on_progress), + "daily_pipeline", + ), + trigger=CronTrigger(day_of_week="mon-fri", + hour=sched["hour"], minute=sched["minute"], + timezone="Asia/Shanghai"), + id="daily_pipeline", + misfire_grace_time=3600, + replace_existing=True, + ) + + scheduler.start() + logger.info("scheduler started; instruments@%02d:%02d, pipeline@%02d:%02d mon-fri", + inst_sched["hour"], inst_sched["minute"], sched["hour"], sched["minute"]) + return scheduler diff --git a/backend/app/main.py b/backend/app/main.py new file mode 100644 index 0000000..6bf6110 --- /dev/null +++ b/backend/app/main.py @@ -0,0 +1,170 @@ +"""FastAPI 入口。""" +from __future__ import annotations + +import logging +from contextlib import asynccontextmanager +from pathlib import Path + +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import FileResponse +from fastapi.staticfiles import StaticFiles + +from app import __version__ +from app.api import analysis, backtest, data, ext_data, financials, indices, intraday, kline, overview, pipeline, screener, settings as settings_api, signals, strategy, watchlist +from app.api.routes import router as core_router +from app.config import settings +from app.jobs import daily_pipeline +from app.services.quote_service import QuoteService +from app.tickflow.policy import detect_capabilities +from app.tickflow.repository import DataStore, KlineRepository + +logging.basicConfig( + level=settings.log_level, + format="%(asctime)s [%(levelname)s] %(name)s: %(message)s", +) +logger = logging.getLogger(__name__) + + +@asynccontextmanager +async def lifespan(app: FastAPI): + logger.info( + "TF-Stocks-Panel v%s starting (mode=%s)", + __version__, "free" if settings.use_free_mode else "api_key", + ) + + # 数据层 + store = DataStore() + repo = KlineRepository(store) + app.state.datastore = store + app.state.repo = repo + + # Polars 缓存预热 + repo.refresh_cache() + + # 能力探测 + capset = detect_capabilities() + app.state.capabilities = capset + logger.info("ready; %d capabilities active", len(capset.all())) + + # 全局行情服务 + qs = QuoteService() + app.state.quote_service = qs + qs.set_repo(repo) + qs.boot_check() + + # QuoteService 需要访问 strategy_monitor 等单例 + # 先创建 strategy_monitor,再注入 app.state + from app.strategy.monitor import StrategyMonitorService + strategy_monitor = StrategyMonitorService() + app.state.strategy_monitor = strategy_monitor + qs.set_app_state(app.state) + + # 启动调度器(若 enriched 数据为空,首次启动可手动 POST /api/pipeline/run) + try: + scheduler = daily_pipeline.start_scheduler(repo, capset) + app.state.scheduler = scheduler + except Exception as e: # noqa: BLE001 + logger.warning("scheduler not started: %s", e) + app.state.scheduler = None + + # 扩展数据定时拉取 + from app.services.ext_pull import pull_scheduler + pull_scheduler.start(store.data_dir) + pull_scheduler.refresh(store.data_dir) + app.state.pull_scheduler = pull_scheduler + + # 财务数据独立调度 (需 Expert 套餐) + from app.services.financial_sync import financial_scheduler + financial_scheduler.start(store.data_dir, capset) + app.state.financial_scheduler = financial_scheduler + + # 策略引擎 + from app.strategy.engine import StrategyEngine + from app.strategy.monitor import StrategyMonitorService + from app.services.screener import ScreenerService + + _screener_svc = ScreenerService(repo) + strategy_dirs = [ + Path(__file__).resolve().parent / "strategy" / "builtin", + store.data_dir / "strategies" / "custom", + store.data_dir / "strategies" / "ai", + ] + strategy_engine = StrategyEngine( + enriched_loader=_screener_svc._load_enriched_for_date, + enriched_history_loader=_screener_svc._load_enriched_history, + strategy_dirs=strategy_dirs, + ) + app.state.strategy_engine = strategy_engine + logger.info("strategy engine loaded: %d strategies", len(strategy_engine.list_strategies())) + + yield + + if app.state.scheduler: + app.state.scheduler.shutdown(wait=False) + ps = getattr(app.state, "pull_scheduler", None) + if ps: + ps.stop() + fsc = getattr(app.state, "financial_scheduler", None) + if fsc: + fsc.stop() + qs = getattr(app.state, "quote_service", None) + if qs: + qs.stop() + logger.info("shutdown") + + +app = FastAPI( + title="TF-Stocks-Panel", + version=__version__, + description="A 股选股 + 回测面板 — TickFlow 适配", + lifespan=lifespan, +) + +# 开发期 CORS 允许 Vite dev server +app.add_middleware( + CORSMiddleware, + allow_origins=["http://localhost:3011", "http://127.0.0.1:3011"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + +# 路由 +app.include_router(core_router) +app.include_router(kline.router) +app.include_router(watchlist.router) +app.include_router(screener.router) +app.include_router(backtest.router) +app.include_router(intraday.router) +app.include_router(indices.router) +app.include_router(overview.router) +app.include_router(analysis.router) +app.include_router(pipeline.router) +app.include_router(data.router) +app.include_router(ext_data.router) +app.include_router(financials.router) +app.include_router(settings_api.router) +app.include_router(strategy.router) +app.include_router(signals.router) + +# 生产期静态文件(前端 dist) +_static = Path(settings.static_dir) +if _static.exists(): + if (_static / "assets").exists(): + app.mount("/assets", StaticFiles(directory=_static / "assets"), name="assets") + + @app.get("/{full_path:path}", include_in_schema=False) + def spa_fallback(full_path: str): # noqa: ARG001 + """所有未匹配路径回退到 index.html — React Router 接管。 + + index.html 禁止缓存 (Cache-Control: no-store), 确保浏览器每次拿到 + 最新版本引用的 JS/CSS 文件名 (assets 带 hash, 可长缓存)。 + """ + index = _static / "index.html" + if index.exists(): + return FileResponse( + index, + headers={"Cache-Control": "no-store, must-revalidate"}, + ) + return {"error": "frontend not built"} diff --git a/backend/app/secrets_store.py b/backend/app/secrets_store.py new file mode 100644 index 0000000..28d2c1b --- /dev/null +++ b/backend/app/secrets_store.py @@ -0,0 +1,96 @@ +"""Key / 凭据本地存储(§14)。 + +存储位置:`data/user_data/secrets.json`,权限 0600。 +优先级:secrets.json > .env > 空(Free 模式)。 + +UI 改 Key 时只动这个文件,不动 .env。 +""" +from __future__ import annotations + +import json +import logging +import os +from pathlib import Path + +logger = logging.getLogger(__name__) + + +def _path() -> Path: + from app.config import settings + p = settings.data_dir / "user_data" / "secrets.json" + p.parent.mkdir(parents=True, exist_ok=True) + return p + + +def load() -> dict: + p = _path() + if p.exists(): + try: + return json.loads(p.read_text(encoding="utf-8")) + except Exception as e: # noqa: BLE001 + logger.warning("secrets.json malformed: %s", e) + return {} + + +def save(updates: dict) -> dict: + """合并写入(不会清掉未提及的字段)。返回新内容。""" + current = load() + current.update({k: v for k, v in updates.items() if v is not None}) + p = _path() + p.write_text(json.dumps(current, indent=2, ensure_ascii=False), encoding="utf-8") + try: + os.chmod(p, 0o600) + except OSError: + pass + return current + + +def clear(*keys: str) -> dict: + """清掉指定字段(留空清全部)。""" + p = _path() + if not p.exists(): + return {} + if not keys: + p.unlink() + return {} + current = load() + for k in keys: + current.pop(k, None) + p.write_text(json.dumps(current, indent=2, ensure_ascii=False), encoding="utf-8") + return current + + +def get_tickflow_key() -> str: + """取当前 TickFlow Key:secrets.json 优先,否则 .env。""" + val = load().get("tickflow_api_key") + if val: + return val + from app.config import settings + return settings.tickflow_api_key or "" + + +def get_ai_key() -> str: + """取当前 AI Key:secrets.json 优先,否则 .env。""" + val = load().get("ai_api_key") + if val: + return val + from app.config import settings + return settings.ai_api_key or "" + + +def get_ai_config(key: str, default: str = "") -> str: + """取 AI 配置项:secrets.json 优先,否则 config。""" + val = load().get(key) + if val: + return val + from app.config import settings + return getattr(settings, key, default) or default + + +def mask(key: str, prefix: int = 4, suffix: int = 4) -> str: + """脱敏显示。""" + if not key: + return "" + if len(key) <= prefix + suffix: + return "•" * len(key) + return f"{key[:prefix]}{'•' * 6}{key[-suffix:]}" diff --git a/backend/app/services/__init__.py b/backend/app/services/__init__.py new file mode 100644 index 0000000..829d0ed --- /dev/null +++ b/backend/app/services/__init__.py @@ -0,0 +1 @@ +"""业务服务层。""" diff --git a/backend/app/services/backtest.py b/backend/app/services/backtest.py new file mode 100644 index 0000000..806541c --- /dev/null +++ b/backend/app/services/backtest.py @@ -0,0 +1,392 @@ +"""回测服务(§6.7)。 + +包 vectorbt — 全项目唯一一处出现 pandas。 +""" +from __future__ import annotations + +import logging +import uuid +from dataclasses import dataclass, field +from datetime import date +from typing import Literal + +import numpy as np +import pandas as pd +import polars as pl + +from app.config import settings +from app.tickflow.repository import KlineRepository + +logger = logging.getLogger(__name__) + +# vectorbt 是 optional extras(见 pyproject.toml).未装时只有 backtest 不可用,其他功能正常. +_vbt = None +_vbt_unavailable_reason: str | None = None + + +class VectorbtUnavailable(RuntimeError): + """vectorbt 未安装 — 提示用户 `uv sync --extra backtest`.""" + + +def _get_vbt(): + global _vbt, _vbt_unavailable_reason + if _vbt is not None: + return _vbt + if _vbt_unavailable_reason is not None: + raise VectorbtUnavailable(_vbt_unavailable_reason) + try: + import vectorbt as vbt + _vbt = vbt + return _vbt + except ImportError as e: + _vbt_unavailable_reason = ( + "vectorbt 未安装 — 它是回测的可选依赖.macOS Intel 用户先 `brew install cmake` " + "然后 `uv sync --extra backtest`" + ) + logger.warning("vectorbt unavailable: %s", e) + raise VectorbtUnavailable(_vbt_unavailable_reason) from e + + +def is_available() -> bool: + """供 API 层快速检测.""" + try: + _get_vbt() + return True + except VectorbtUnavailable: + return False + + +SignalKind = Literal[ + "macd_golden", "macd_dead", + "ma_golden_5_20", "ma_dead_5_20", + "ma_golden_20_60", + "ma20_breakout", "ma20_breakdown", + "n_day_high", "n_day_low", + "boll_breakout_upper", "boll_breakdown_lower", + "volume_surge", + "rsi_oversold", "rsi_overbought", + "stop_loss", "trailing_stop", "max_hold", +] + + +@dataclass +class BacktestConfig: + symbols: list[str] + start: date + end: date + # 买入信号(任一触发即买) + entries: list[str] = field(default_factory=list) + # 卖出信号(任一触发即卖) + exits: list[str] = field(default_factory=list) + # 其他参数 + stop_loss_pct: float | None = None # 例 -0.05 = -5% + max_hold_days: int | None = None + fees_pct: float = 0.0002 # 万二佣金 + slippage_bps: float = 5 # 5 bps + # 撮合 + matching: Literal["close_t", "open_t+1"] = "close_t" + rsi_oversold_threshold: float = 30 + rsi_overbought_threshold: float = 70 + + +@dataclass +class BacktestResult: + run_id: str + config: dict + stats: dict + equity_curve: list[dict] # [{date, value}] + trades: list[dict] # [{symbol, entry_date, exit_date, pnl_pct, ...}] + per_symbol_stats: list[dict] # 每只股票的统计 + + +# enriched 表里的信号列名映射 +_SIGNAL_COLS: dict[SignalKind, str] = { + "macd_golden": "signal_macd_golden", + "macd_dead": "signal_macd_dead", + "ma_golden_5_20": "signal_ma_golden_5_20", + "ma_dead_5_20": "signal_ma_dead_5_20", + "ma_golden_20_60": "signal_ma_golden_20_60", + "ma20_breakout": "signal_ma20_breakout", + "ma20_breakdown": "signal_ma20_breakdown", + "n_day_high": "signal_n_day_high", + "n_day_low": "signal_n_day_low", + "boll_breakout_upper": "signal_boll_breakout_upper", + "boll_breakdown_lower": "signal_boll_breakdown_lower", + "volume_surge": "signal_volume_surge", +} + + +class BacktestService: + def __init__(self, repo: KlineRepository) -> None: + self.repo = repo + + def _load_panel( + self, + symbols: list[str], + start: date, + end: date, + ) -> pd.DataFrame: + """加载 [date × symbol] 价格面板 — Polars scan_parquet + 即时计算指标。 + + **全项目唯一从 Polars 转 pandas 的边界**(§7.4 / ADR-19)。 + """ + try: + enriched_glob = str(self.repo.store.data_dir / "kline_daily_enriched" / "**" / "*.parquet") + df = ( + pl.scan_parquet(enriched_glob) + .filter( + (pl.col("symbol").is_in(symbols)) + & (pl.col("date") >= start) + & (pl.col("date") <= end) + ) + .sort(["date", "symbol"]) + .collect() + ) + except Exception as e: # noqa: BLE001 + logger.warning("backtest load failed: %s", e) + return pd.DataFrame() + + if df.is_empty(): + return pd.DataFrame() + + # 即时计算指标 + 信号 + from app.indicators.pipeline import compute_all + df = compute_all(df) + + # 选择需要的列 + needed_cols = [ + "date", "symbol", "open", "high", "low", "close", "volume", + "rsi_14", "signal_macd_golden", "signal_macd_dead", + "signal_ma_golden_5_20", "signal_ma_dead_5_20", + "signal_ma_golden_20_60", + "signal_ma20_breakout", "signal_ma20_breakdown", + "signal_n_day_high", "signal_n_day_low", + "signal_boll_breakout_upper", "signal_boll_breakdown_lower", + "signal_volume_surge", + ] + existing = [c for c in needed_cols if c in df.columns] + df = df.select(existing) + + # to_pandas 边界 + return df.to_pandas(use_pyarrow_extension_array=False) + + def _build_signal_matrix( + self, + panel: pd.DataFrame, + kinds: list[str], + config: BacktestConfig, + ) -> pd.DataFrame: + """从面板构造 [date × symbol] 的布尔信号矩阵。""" + if not kinds or panel.empty: + return pd.DataFrame() + + # pivot 成 [date × symbol] 形式 + result = None + for kind in kinds: + mat = None + if kind in _SIGNAL_COLS: + col = _SIGNAL_COLS[kind] + mat = panel.pivot(index="date", columns="symbol", values=col).fillna(False).astype(bool) + elif kind == "rsi_oversold": + mat = (panel.pivot(index="date", columns="symbol", values="rsi_14") + < config.rsi_oversold_threshold) + elif kind == "rsi_overbought": + mat = (panel.pivot(index="date", columns="symbol", values="rsi_14") + > config.rsi_overbought_threshold) + # stop_loss / trailing / max_hold 通过 vectorbt 参数处理,不参与信号矩阵 + + if mat is not None: + result = mat if result is None else (result | mat) + return result if result is not None else pd.DataFrame() + + def run(self, config: BacktestConfig) -> BacktestResult: + vbt = _get_vbt() + run_id = uuid.uuid4().hex[:10] + + panel = self._load_panel(config.symbols, config.start, config.end) + if panel.empty: + return BacktestResult( + run_id=run_id, + config=_config_to_dict(config), + stats={"error": "no data"}, + equity_curve=[], + trades=[], + per_symbol_stats=[], + ) + + # 价格面板 + close = panel.pivot(index="date", columns="symbol", values="close") + + # 信号矩阵 + entries = self._build_signal_matrix(panel, config.entries, config) + exits = self._build_signal_matrix(panel, config.exits, config) + + # 对齐 index/columns + if not entries.empty: + entries = entries.reindex_like(close).fillna(False).astype(bool) + else: + entries = pd.DataFrame(False, index=close.index, columns=close.columns) + if not exits.empty: + exits = exits.reindex_like(close).fillna(False).astype(bool) + else: + exits = pd.DataFrame(False, index=close.index, columns=close.columns) + + if not entries.any().any(): + return BacktestResult( + run_id=run_id, + config=_config_to_dict(config), + stats={"error": "no buy signals"}, + equity_curve=[], + trades=[], + per_symbol_stats=[], + ) + + # T+1 适配:vectorbt 默认信号当根 K 撮合 + # close_t 撮合:维持默认 + # open_t+1 撮合:shift 信号 1 根 + 用 open 作为价 + if config.matching == "open_t+1": + entries = entries.shift(1).fillna(False).astype(bool) + exits = exits.shift(1).fillna(False).astype(bool) + price = panel.pivot(index="date", columns="symbol", values="open") + else: + price = close + + # 跑回测 + try: + pf_kwargs = dict( + close=close, + entries=entries, + exits=exits, + price=price, + fees=config.fees_pct, + slippage=config.slippage_bps / 10000.0, + freq="1D", + ) + if config.stop_loss_pct is not None: + pf_kwargs["sl_stop"] = abs(config.stop_loss_pct) + if config.max_hold_days is not None: + # vectorbt 没有内置 max-hold;用时间退出近似: + # 在 max_hold_days 后强制 exit + exits_idx = entries.copy() + for col in entries.columns: + entry_rows = np.where(entries[col].values)[0] + for i in entry_rows: + end_i = min(i + config.max_hold_days, len(entries) - 1) + if end_i > i: + exits_idx.iloc[end_i][col] = True + pf_kwargs["exits"] = (exits | exits_idx).astype(bool) + + pf = vbt.Portfolio.from_signals(**pf_kwargs) + except Exception as e: # noqa: BLE001 + logger.exception("vectorbt backtest failed") + return BacktestResult( + run_id=run_id, + config=_config_to_dict(config), + stats={"error": str(e)}, + equity_curve=[], + trades=[], + per_symbol_stats=[], + ) + + # 提取结果 + try: + stats_series = pf.stats(silence_warnings=True) + if isinstance(stats_series, pd.DataFrame): + # 多列时取 agg + stats_dict = stats_series.mean(numeric_only=True).to_dict() + else: + stats_dict = stats_series.to_dict() + except Exception: # noqa: BLE001 + stats_dict = {} + + # 净值曲线(组合平均) + equity = pf.value().mean(axis=1) if isinstance(pf.value(), pd.DataFrame) else pf.value() + equity_curve = [ + {"date": str(idx.date() if hasattr(idx, "date") else idx), "value": float(v)} + for idx, v in equity.items() if pd.notna(v) + ] + + # 交易记录 + try: + trades_df = pf.trades.records_readable + trades = trades_df.to_dict(orient="records") if not trades_df.empty else [] + # 字段名美化 + trades = [ + { + "symbol": t.get("Column", t.get("Symbol", "")), + "entry_date": str(t.get("Entry Timestamp", t.get("Entry Date", ""))), + "exit_date": str(t.get("Exit Timestamp", t.get("Exit Date", ""))), + "entry_price": float(t.get("Avg Entry Price", t.get("Avg. Entry Price", 0))), + "exit_price": float(t.get("Avg Exit Price", t.get("Avg. Exit Price", 0))), + "pnl_pct": float(t.get("Return", t.get("PnL %", 0))), + "duration": str(t.get("Duration", "")), + } + for t in trades + ] + except Exception: # noqa: BLE001 + trades = [] + + # 每标的统计 + per_symbol = [] + try: + total_ret = pf.total_return() + if isinstance(total_ret, pd.Series): + for sym, ret in total_ret.items(): + if pd.notna(ret): + per_symbol.append({"symbol": sym, "total_return": float(ret)}) + except Exception: # noqa: BLE001 + pass + + result = BacktestResult( + run_id=run_id, + config=_config_to_dict(config), + stats={k: _json_safe(v) for k, v in stats_dict.items()}, + equity_curve=equity_curve, + trades=trades, + per_symbol_stats=per_symbol, + ) + + # 落盘 + self._persist(result) + return result + + def _persist(self, result: BacktestResult) -> None: + out_dir = settings.data_dir / "backtest_results" + out_dir.mkdir(parents=True, exist_ok=True) + # 用 polars 写一份汇总 + summary = pl.DataFrame({ + "run_id": [result.run_id], + "stats_json": [str(result.stats)], + "n_trades": [len(result.trades)], + }) + summary.write_parquet(out_dir / f"run_id={result.run_id}.parquet") + + def get_result(self, run_id: str) -> BacktestResult | None: + # Phase 1:只保留近似落盘,完整结果保存在内存的近期 cache 中 + # 简化:重新 run 比缓存复杂结果代价小,暂不实现 get_result + return None + + +def _config_to_dict(c: BacktestConfig) -> dict: + return { + "symbols": c.symbols, + "start": str(c.start), + "end": str(c.end), + "entries": c.entries, + "exits": c.exits, + "stop_loss_pct": c.stop_loss_pct, + "max_hold_days": c.max_hold_days, + "fees_pct": c.fees_pct, + "slippage_bps": c.slippage_bps, + "matching": c.matching, + } + + +def _json_safe(v): + if isinstance(v, (int, float, str, bool)) or v is None: + return v + if isinstance(v, (np.floating, np.integer)): + return float(v) if not np.isnan(float(v)) else None + if hasattr(v, "isoformat"): + return v.isoformat() + return str(v) diff --git a/backend/app/services/ext_data.py b/backend/app/services/ext_data.py new file mode 100644 index 0000000..1ce4ad5 --- /dev/null +++ b/backend/app/services/ext_data.py @@ -0,0 +1,483 @@ +"""扩展数据服务 — 配置管理 + 文件解析 + Parquet 存储。""" +from __future__ import annotations + +import json +import logging +from datetime import date, datetime +from pathlib import Path +from typing import Literal + +import polars as pl + +logger = logging.getLogger(__name__) + +# --------------------------------------------------------------------------- +# 配置模型 +# --------------------------------------------------------------------------- + +class ExtField: + """扩展字段定义。""" + __slots__ = ("name", "dtype", "label") + + def __init__(self, name: str, dtype: str = "string", label: str = "") -> None: + self.name = name + self.dtype = dtype # string | int | float | bool + self.label = label or name + + def to_dict(self) -> dict: + return {"name": self.name, "dtype": self.dtype, "label": self.label} + + @classmethod + def from_dict(cls, d: dict) -> ExtField: + return cls(d["name"], d.get("dtype", "string"), d.get("label", "")) + + +class PullConfig: + """定时拉取配置。""" + __slots__ = ( + "url", "method", "headers", "body", "response_path", + "field_map", "schedule_minutes", "enabled", + "last_run", "last_status", "last_message", "last_rows", + ) + + def __init__( + self, + url: str = "", + method: str = "GET", + headers: dict[str, str] | None = None, + body: str | None = None, + response_path: str = "", + field_map: dict[str, str] | None = None, + schedule_minutes: int = 1440, + enabled: bool = False, + last_run: str | None = None, + last_status: str | None = None, + last_message: str | None = None, + last_rows: int | None = None, + ) -> None: + self.url = url + self.method = method # GET | POST + self.headers = headers or {} + self.body = body # JSON string (POST body template) + self.response_path = response_path # dot-path to rows array, e.g. "data.list" + self.field_map = field_map or {} # external_name → config_field_name + self.schedule_minutes = schedule_minutes + self.enabled = enabled + self.last_run = last_run + self.last_status = last_status # "success" | "error" + self.last_message = last_message + self.last_rows = last_rows + + def to_dict(self) -> dict: + return { + "url": self.url, + "method": self.method, + "headers": self.headers, + "body": self.body, + "response_path": self.response_path, + "field_map": self.field_map, + "schedule_minutes": self.schedule_minutes, + "enabled": self.enabled, + "last_run": self.last_run, + "last_status": self.last_status, + "last_message": self.last_message, + "last_rows": self.last_rows, + } + + @classmethod + def from_dict(cls, d: dict) -> PullConfig: + if not d: + return cls() + return cls( + url=d.get("url", ""), + method=d.get("method", "GET"), + headers=d.get("headers"), + body=d.get("body"), + response_path=d.get("response_path", ""), + field_map=d.get("field_map"), + schedule_minutes=d.get("schedule_minutes", 1440), + enabled=d.get("enabled", False), + last_run=d.get("last_run"), + last_status=d.get("last_status"), + last_message=d.get("last_message"), + last_rows=d.get("last_rows"), + ) + + +class ExtConfig: + """一个扩展数据源的完整配置。""" + __slots__ = ( + "id", "label", "mode", "fields", "description", + "symbol_map", "code_map", + "created_at", "updated_at", "pull", + ) + + def __init__( + self, + id: str, + label: str, + mode: Literal["snapshot", "timeseries"], + fields: list[ExtField], + description: str = "", + symbol_map: dict | None = None, + code_map: dict | None = None, + created_at: str | None = None, + updated_at: str | None = None, + pull: PullConfig | None = None, + ) -> None: + self.id = id + self.label = label + self.mode = mode + self.fields = fields + self.description = description + # 映射关系: {"type": "mapped", "col": "原始列名"} 或 {"type": "computed", "from": "symbol|code", "method": "strip_exchange|append_exchange"} + self.symbol_map = symbol_map or {} + self.code_map = code_map or {} + self.created_at = created_at or datetime.now().isoformat() + self.updated_at = updated_at or datetime.now().isoformat() + self.pull = pull + + def to_dict(self) -> dict: + d = { + "id": self.id, + "label": self.label, + "mode": self.mode, + "fields": [f.to_dict() for f in self.fields], + "description": self.description, + "symbol_map": self.symbol_map, + "code_map": self.code_map, + "created_at": self.created_at, + "updated_at": self.updated_at, + } + if self.pull: + d["pull"] = self.pull.to_dict() + return d + + @classmethod + def from_dict(cls, d: dict) -> ExtConfig: + return cls( + id=d["id"], + label=d["label"], + mode=d["mode"], + fields=[ExtField.from_dict(f) for f in d.get("fields", [])], + description=d.get("description", ""), + symbol_map=d.get("symbol_map"), + code_map=d.get("code_map"), + created_at=d.get("created_at"), + updated_at=d.get("updated_at"), + pull=PullConfig.from_dict(d["pull"]) if d.get("pull") else None, + ) + + +# --------------------------------------------------------------------------- +# 配置持久化 +# --------------------------------------------------------------------------- + +class ExtConfigStore: + """扩展数据配置文件读写 — 每个表独立目录 data/ext/{config_id}/config.json。""" + + def __init__(self, data_dir: Path) -> None: + self._base = data_dir / "ext_data" + + def _config_path(self, config_id: str) -> Path: + return self._base / config_id / "config.json" + + def load_all(self) -> list[ExtConfig]: + # 兼容旧版: 如果目录为空且旧配置文件存在则迁移 + if not self._base.exists() or not any(self._base.iterdir()): + old = self._base.parent / "ext_configs.json" + if not old.exists(): + old = self._base.parent / "ext_configs.json.bak" + if old.exists(): + self._migrate_legacy(old) + if not self._base.exists(): + return [] + configs = [] + for d in sorted(self._base.iterdir()): + cp = d / "config.json" + if d.is_dir() and cp.exists(): + try: + raw = json.loads(cp.read_text(encoding="utf-8")) + configs.append(ExtConfig.from_dict(raw)) + except Exception as e: + logger.warning("扩展表配置解析失败 %s: %s", cp, e) + return configs + + def get(self, config_id: str) -> ExtConfig | None: + cp = self._config_path(config_id) + if not cp.exists(): + return None + try: + raw = json.loads(cp.read_text(encoding="utf-8")) + return ExtConfig.from_dict(raw) + except Exception: + return None + + def upsert(self, config: ExtConfig) -> None: + config.updated_at = datetime.now().isoformat() + cp = self._config_path(config.id) + cp.parent.mkdir(parents=True, exist_ok=True) + cp.write_text( + json.dumps(config.to_dict(), ensure_ascii=False, indent=2), + encoding="utf-8", + ) + + def delete(self, config_id: str) -> bool: + import shutil + cp = self._config_path(config_id) + if not cp.exists(): + return False + shutil.rmtree(cp.parent, ignore_errors=True) + return True + + def _migrate_legacy(self, old_path: Path) -> None: + """一次性迁移旧版 ext_configs.json 到独立目录结构。""" + try: + raw = json.loads(old_path.read_text(encoding="utf-8")) + configs = [ExtConfig.from_dict(d) for d in raw] + for c in configs: + cp = self._config_path(c.id) + cp.parent.mkdir(parents=True, exist_ok=True) + cp.write_text( + json.dumps(c.to_dict(), ensure_ascii=False, indent=2), + encoding="utf-8", + ) + # 迁移完成后重命名旧文件作为备份 + backup = old_path.with_suffix(".json.bak") + old_path.rename(backup) + logger.info("ext_configs.json 已迁移至 ext/ (备份: %s)", backup.name) + except Exception as e: + logger.warning("ext_configs 迁移失败: %s", e) + + +# --------------------------------------------------------------------------- +# CSV / Excel 解析 → Parquet 写入 +# --------------------------------------------------------------------------- + +_POLARS_DTYPE_MAP = { + "string": pl.Utf8, + "int": pl.Int64, + "float": pl.Float64, + "bool": pl.Boolean, +} + + +def build_code_lookup(data_dir: Path) -> dict[str, str]: + """从 instruments 维表构建 code → symbol 映射。""" + path = data_dir / "instruments" / "instruments.parquet" + if not path.exists(): + return {} + try: + df = pl.read_parquet(path, columns=["code", "symbol"]) + return dict(zip(df["code"].to_list(), df["symbol"].to_list())) + except Exception: + return {} + + +def normalize_symbol(series: pl.Series, lookup: dict[str, str] | None = None) -> pl.Series: + """将 symbol 列标准化为 代码.交易所 格式。 + + 优先使用 instruments 维表查找 code → symbol,确保 100% 准确。 + 查不到时按规则兜底:6开头 → .SH,其余 → .SZ。 + """ + _lookup = lookup or {} + + def _fix_one(val: str) -> str: + if not val: + return val + val = val.strip() + # 已经是标准格式(含 .),直接返回 + if "." in val: + return val + # 纯6位数字代码 → 优先查维表 + if len(val) == 6 and val.isdigit(): + mapped = _lookup.get(val) + if mapped: + return mapped + # 兜底规则 + if val.startswith(("6",)): + return f"{val}.SH" + else: + return f"{val}.SZ" + return val + + return series.map_elements(_fix_one, return_dtype=pl.Utf8) + + +def parse_upload_file(file_path: Path, symbol_col: str = "symbol", data_dir: Path | None = None) -> pl.DataFrame: + """解析上传的 CSV / Excel 文件为 Polars DataFrame。""" + suffix = file_path.suffix.lower() + if suffix == ".csv": + df = pl.read_csv(file_path, infer_schema_length=10000) + elif suffix in (".xlsx", ".xls"): + df = pl.read_excel(file_path) + else: + raise ValueError(f"不支持的文件格式: {suffix}") + + if symbol_col not in df.columns: + # 尝试模糊匹配 + candidates = [c for c in df.columns if c.lower() in ("symbol", "code", "代码", "标的")] + if candidates: + df = df.rename({candidates[0]: symbol_col}) + else: + raise ValueError(f"未找到标的代码列 (symbol),可选列: {df.columns}") + + # 确保 symbol 列为字符串并标准化 + lookup = build_code_lookup(data_dir) if data_dir else None + df = df.with_columns(normalize_symbol(df[symbol_col].cast(pl.Utf8), lookup)) + return df + + +def cast_df_to_schema(df: pl.DataFrame, fields: list[ExtField]) -> pl.DataFrame: + """按配置的字段类型转换 DataFrame 列类型。""" + for f in fields: + if f.name in df.columns: + target = _POLARS_DTYPE_MAP.get(f.dtype, pl.Utf8) + df = df.with_columns(pl.col(f.name).cast(target)) + return df + + +def _config_dir(config_id: str, data_dir: Path) -> Path: + """返回扩展配置的根目录 data/ext_data/{config_id}/。""" + return data_dir / "ext_data" / config_id + + +def write_ext_parquet( + df: pl.DataFrame, + config: ExtConfig, + data_dir: Path, + snapshot_date: date | None = None, +) -> int: + """将 DataFrame 写入扩展数据 Parquet。 + + 目录结构: + - snapshot: data/ext_data/{id}/part.parquet(与 config.json 同级,覆盖写) + - timeseries: data/ext_data/{id}/timeseries/date=xxx/part.parquet(按日分区) + + Returns: + 写入行数。 + """ + snap = snapshot_date or date.today() + cfg_dir = _config_dir(config.id, data_dir) + + # 标准化 symbol 列: 用维表查找 → 准确匹配交易所 + if "symbol" in df.columns: + lookup = build_code_lookup(data_dir) + df = df.with_columns(normalize_symbol(df["symbol"], lookup)) + + if config.mode == "snapshot": + # 快照: 与 config.json 同级,直接覆盖 + cfg_dir.mkdir(parents=True, exist_ok=True) + out_path = cfg_dir / "part.parquet" + + # 如果已有文件,合并去重后覆盖 + if out_path.exists(): + try: + existing = pl.read_parquet(out_path) + key = "symbol" if "symbol" in df.columns else df.columns[0] + df = pl.concat([existing, df]).unique(subset=[key], keep="last") + except Exception: + pass + else: + # 时序: timeseries/ 下按日期分区 + out_dir = cfg_dir / "timeseries" / f"date={snap}" + out_dir.mkdir(parents=True, exist_ok=True) + out_path = out_dir / "part.parquet" + + # 如果已有文件,合并去重 + if out_path.exists(): + try: + existing = pl.read_parquet(out_path) + key = "symbol" if "symbol" in df.columns else df.columns[0] + df = pl.concat([existing, df]).unique(subset=[key], keep="last") + except Exception: + pass + + df = cast_df_to_schema(df, config.fields) + df.write_parquet(out_path) + logger.info("扩展表写入: %s → %s (%d 行)", config.id, out_path, len(df)) + return len(df) + + +def delete_ext_parquet(config_id: str, data_dir: Path) -> None: + """删除扩展数据源关联的所有 Parquet 数据(保留 config.json)。 + + - snapshot: 删除 ext_data/{id}/part.parquet + - timeseries: 删除 ext_data/{id}/timeseries/ 目录 + """ + cfg_dir = _config_dir(config_id, data_dir) + # 删除快照文件 + snap = cfg_dir / "part.parquet" + if snap.exists(): + snap.unlink() + # 删除时序目录 + ts_dir = cfg_dir / "timeseries" + if ts_dir.exists(): + import shutil + shutil.rmtree(ts_dir, ignore_errors=True) + + +def fix_symbol_format(config: ExtConfig, data_dir: Path) -> int: + """扫描该扩展配置的所有 Parquet 文件,将 symbol 列标准化为 代码.交易所 格式。 + + - snapshot: 扫描 ext_data/{id}/part.parquet + - timeseries: 扫描 ext_data/{id}/timeseries/date=xxx/part.parquet + + Returns: + 修复的文件数。 + """ + cfg_dir = _config_dir(config.id, data_dir) + if not cfg_dir.exists(): + return 0 + + # 收集需要扫描的 parquet 文件列表 + parquet_files: list[Path] = [] + if config.mode == "snapshot": + p = cfg_dir / "part.parquet" + if p.exists(): + parquet_files.append(p) + else: + ts_dir = cfg_dir / "timeseries" + if ts_dir.exists(): + for part_dir in sorted(ts_dir.iterdir()): + if not part_dir.is_dir() or not part_dir.name.startswith("date="): + continue + p = part_dir / "part.parquet" + if p.exists(): + parquet_files.append(p) + + fixed = 0 + lookup = build_code_lookup(data_dir) + for parquet_path in parquet_files: + try: + df = pl.read_parquet(parquet_path) + if "symbol" not in df.columns: + continue + old = df["symbol"].to_list() + df = df.with_columns(normalize_symbol(df["symbol"], lookup)) + new = df["symbol"].to_list() + if old != new: + df.write_parquet(parquet_path) + fixed += 1 + logger.info("代码格式修复: %s/%s (%d 行)", config.id, parquet_path.parent.name, len(df)) + except Exception as e: + logger.warning("代码格式修复跳过 %s: %s", parquet_path, e) + + return fixed + + +def rows_to_parquet( + rows: list[dict], + config: ExtConfig, + data_dir: Path, + snapshot_date: date | None = None, +) -> int: + """将 JSON 行列表转为 DataFrame 写入 Parquet,复用 write_ext_parquet 的存储逻辑。 + + Returns: + 写入行数。 + """ + df = pl.DataFrame(rows) + if "symbol" in df.columns: + df = df.with_columns(pl.col("symbol").cast(pl.Utf8)) + return write_ext_parquet(df, config, data_dir, snapshot_date=snapshot_date) diff --git a/backend/app/services/ext_pull.py b/backend/app/services/ext_pull.py new file mode 100644 index 0000000..d15a638 --- /dev/null +++ b/backend/app/services/ext_pull.py @@ -0,0 +1,216 @@ +"""扩展数据定时拉取引擎 — 从外部 API 拉取数据写入 Parquet。""" +from __future__ import annotations + +import asyncio +import json +import logging +import threading +from datetime import date, datetime, timezone +from functools import reduce +from typing import Any + +import httpx + +from app.services.ext_data import ( + ExtConfig, + ExtConfigStore, + PullConfig, + rows_to_parquet, +) + +logger = logging.getLogger(__name__) + + +# --------------------------------------------------------------------------- +# 响应解析 +# --------------------------------------------------------------------------- + +def _extract_rows(data: Any, path: str) -> list[dict]: + """按 dot-path 从 JSON 响应中提取行数组。 + + 例: path="data.list" → response["data"]["list"] + 如果 path 为空,直接将 data 视为数组。 + """ + if not path: + if isinstance(data, list): + return data + raise ValueError("response_path 为空但响应不是数组") + + keys = path.split(".") + current = data + for key in keys: + if isinstance(current, dict): + if key not in current: + raise ValueError(f"响应中不存在路径 '{path}',缺失键 '{key}'") + current = current[key] + elif isinstance(current, list): + try: + current = current[int(key)] + except (ValueError, IndexError) as e: + raise ValueError(f"响应路径 '{path}' 解析失败: {e}") from e + else: + raise ValueError(f"响应路径 '{path}' 中间值不是 dict/list: {type(current)}") + + if not isinstance(current, list): + raise ValueError(f"路径 '{path}' 指向的不是数组,而是 {type(current)}") + + return current + + +def _apply_field_map(rows: list[dict], field_map: dict[str, str]) -> list[dict]: + """将外部字段名映射为内部配置字段名。field_map: {外部名: 内部名}。""" + if not field_map: + return rows + mapped = [] + for row in rows: + new_row: dict = {} + for k, v in row.items(): + mapped_key = field_map.get(k, k) + new_row[mapped_key] = v + mapped.append(new_row) + return mapped + + +# --------------------------------------------------------------------------- +# 拉取执行 +# --------------------------------------------------------------------------- + +async def fetch_and_ingest( + config: ExtConfig, + data_dir, +) -> tuple[int, str]: + """执行一次拉取: 请求外部 API → 解析响应 → 写入 Parquet。 + + Returns: + (rows_written, date_str) + """ + pull = config.pull + if not pull or not pull.url: + raise ValueError("拉取未配置或 URL 为空") + + async with httpx.AsyncClient(timeout=30) as client: + headers = pull.headers or {} + kwargs: dict[str, Any] = {"headers": headers} + + if pull.method.upper() == "POST" and pull.body: + kwargs["content"] = pull.body + if "content-type" not in {k.lower() for k in headers}: + kwargs["headers"]["Content-Type"] = "application/json" + + resp = await client.request(pull.method.upper(), pull.url, **kwargs) + resp.raise_for_status() + + # 解析 JSON + try: + data = resp.json() + except Exception as e: + raise ValueError(f"响应不是有效 JSON: {e}") from e + + # 提取行 + rows = _extract_rows(data, pull.response_path) + if not rows: + raise ValueError("提取到的行数为 0") + + # 字段映射 + rows = _apply_field_map(rows, pull.field_map) + + # 校验 symbol 列 + if rows and "symbol" not in rows[0]: + raise ValueError("数据行中缺少 symbol 字段,请配置 field_map 映射") + + # 写入 + snap = date.today() + n = rows_to_parquet(rows, config, data_dir, snapshot_date=snap) + return n, snap.isoformat() + + +# --------------------------------------------------------------------------- +# 调度器 +# --------------------------------------------------------------------------- + +class PullScheduler: + """后台调度器:为每个启用了 pull 的 ExtConfig 维护定时任务。""" + + def __init__(self) -> None: + self._tasks: dict[str, asyncio.Task] = {} + self._running = False + self._lock = threading.Lock() + + def start(self, data_dir) -> None: + """启动调度(在 lifespan startup 调用)。""" + self._running = True + self._data_dir = data_dir + logger.info("PullScheduler started") + + def stop(self) -> None: + """停止所有任务。""" + self._running = False + for task in self._tasks.values(): + task.cancel() + self._tasks.clear() + logger.info("PullScheduler stopped") + + def refresh(self, data_dir) -> None: + """重新加载配置,更新调度任务(增/删/改)。""" + self._data_dir = data_dir + store = ExtConfigStore(data_dir) + configs = store.load_all() + + active_ids: set[str] = set() + + for config in configs: + if not config.pull or not config.pull.enabled or not config.pull.url: + continue + active_ids.add(config.id) + if config.id not in self._tasks: + # 新增调度 + task = asyncio.create_task(self._run_loop(config)) + self._tasks[config.id] = task + logger.info("PullScheduler: scheduled %s (every %d min)", config.id, config.pull.schedule_minutes) + + # 移除不再活跃的 + for cid in list(self._tasks): + if cid not in active_ids: + self._tasks[cid].cancel() + del self._tasks[cid] + logger.info("PullScheduler: removed %s", cid) + + async def _run_loop(self, config: ExtConfig) -> None: + """单个配置的定时拉取循环。""" + try: + while self._running: + pull = config.pull + if not pull: + break + interval = max(pull.schedule_minutes * 60, 60) # 至少 60s + await asyncio.sleep(interval) + if not self._running: + break + try: + # 重新加载最新配置(用户可能中途修改) + store = ExtConfigStore(self._data_dir) + fresh = store.get(config.id) + if not fresh or not fresh.pull or not fresh.pull.enabled: + break + n, d = await fetch_and_ingest(fresh, self._data_dir) + fresh.pull.last_run = datetime.now(timezone.utc).isoformat() + fresh.pull.last_status = "success" + fresh.pull.last_message = f"{n} rows @ {d}" + fresh.pull.last_rows = n + store.upsert(fresh) + logger.info("PullScheduler: %s success, %d rows", config.id, n) + except Exception as e: + store = ExtConfigStore(self._data_dir) + fresh = store.get(config.id) + if fresh and fresh.pull: + fresh.pull.last_run = datetime.now(timezone.utc).isoformat() + fresh.pull.last_status = "error" + fresh.pull.last_message = str(e)[:200] + store.upsert(fresh) + logger.warning("PullScheduler: %s error: %s", config.id, e) + except asyncio.CancelledError: + pass + + +# 全局单例 +pull_scheduler = PullScheduler() diff --git a/backend/app/services/extend_history.py b/backend/app/services/extend_history.py new file mode 100644 index 0000000..1339a52 --- /dev/null +++ b/backend/app/services/extend_history.py @@ -0,0 +1,224 @@ +"""向前扩展历史数据 — 完全独立于 daily_pipeline 的盘后管道。 + +用户从日 K 卡片手动触发,指定往前补的时长 (x 天/月/年)。 +流程: + 1. 获取当前最早日期 + 2. 向前拉日 K batch (start = 最早日期 - offset, end = 最早日期) + 3. 向前拉除权因子 (同范围) + 4. 全量重算 enriched + 5. 刷新视图 + 缓存 + +⚠️ 本模块不导入 daily_pipeline 的任何函数,只复用基础设施: + - kline_sync.sync_and_persist_daily_batch / sync_adj_factor + - indicators.pipeline.run_pipeline + - pipeline_jobs.JobStore + - tickflow.repository.KlineRepository +""" +from __future__ import annotations + +import logging +from collections.abc import Callable +from datetime import date, datetime, timedelta + +from app.services import kline_sync +from app.services.pipeline_jobs import job_store +from app.tickflow.capabilities import Cap, CapabilitySet +from app.tickflow.repository import KlineRepository + +logger = logging.getLogger(__name__) + + +def _noop(stage: str, pct: int, msg: str, **kwargs) -> None: # noqa: ARG001 + pass + + +def _invalidate(table: str | None = None) -> None: + from app.api.data import invalidate_data_cache + invalidate_data_cache(table) + + +def _resolve_universe(capset: CapabilitySet) -> list[str]: + """解析标的池 — 与 daily_pipeline 独立的副本。""" + if capset.has(Cap.KLINE_DAILY_BATCH): + try: + from app.tickflow.pools import get_pool + all_a = get_pool("CN_Equity_A", refresh=True) + if all_a: + return sorted(all_a) + except Exception as e: + logger.warning("CN_Equity_A pool unavailable: %s", e) + + from app.tickflow.pools import DEMO_SYMBOLS, get_pool as _get_pool + from app.config import settings + from pathlib import Path + import polars as pl + base: set[str] = set(DEMO_SYMBOLS) + base.update(_get_pool("watchlist")) + d = Path(settings.data_dir) + inst_path = d / "instruments" / "instruments.parquet" + if inst_path.exists(): + try: + inst = pl.read_parquet(inst_path, columns=["symbol"]) + base.update(inst["symbol"].to_list()) + except Exception as e: + logger.warning("instruments supplement failed: %s", e) + return sorted(base) + + +def _refresh_single_view(repo: KlineRepository, name: str) -> None: + """刷新单个 DuckDB 视图。""" + d = repo.store.data_dir.as_posix() + paths = { + "kline_daily": f"{d}/kline_daily/**/*.parquet", + "kline_enriched": f"{d}/kline_daily_enriched/**/*.parquet", + "kline_minute": f"{d}/kline_minute/**/*.parquet", + "adj_factor": f"{d}/adj_factor/**/*.parquet", + "instruments": f"{d}/instruments/**/*.parquet", + } + path = paths.get(name) + if not path: + return + try: + repo.db.execute( + f"CREATE OR REPLACE VIEW {name} AS " + f"SELECT * FROM read_parquet('{path}', union_by_name=true)" + ) + except Exception as e: + logger.warning("refresh view %s failed: %s", name, e) + + +def compute_offset(value: int, unit: str) -> timedelta: + """将用户输入的 value + unit 转成 timedelta。""" + if unit == "day": + return timedelta(days=value) + elif unit == "month": + return timedelta(days=value * 30) + elif unit == "year": + return timedelta(days=value * 365) + else: + raise ValueError(f"不支持的单位: {unit}") + + +def run_extend_history( + repo: KlineRepository, + capset: CapabilitySet, + value: int, + unit: str, + on_progress: Callable | None = None, +) -> dict: + """向前扩展历史数据的主函数。 + + 完全独立于 daily_pipeline.run_now(),不调用其任何逻辑。 + 返回结果 dict 供 job_store 记录。 + """ + emit = on_progress or _noop + + # 0. 计算时间偏移 + offset = compute_offset(value, unit) + today = date.today() + + # 1. 获取当前最早日期 + emit("extend_history", 2, "检查当前数据范围…") + earliest = repo.earliest_daily_date() + + if not earliest: + return {"error": "本地无日K数据,请先执行一次完整同步"} + + new_start = earliest - offset + # 不能超过今天 + if new_start >= earliest: + return {"error": "扩展范围无效,请增大时间跨度"} + + # 2. 解析标的池 + emit("extend_history", 5, "解析标的池…") + universe = _resolve_universe(capset) + if not universe: + return {"error": "标的池为空"} + emit("extend_history", 8, f"标的池: {len(universe)} 只") + + start_str = new_start.strftime("%Y-%m-%d") + end_str = earliest.strftime("%Y-%m-%d") + + # 3. 拉日 K + emit("extend_history", 10, f"获取日K [{start_str} ~ {end_str}]…") + logger.info("extend_history: daily K [%s ~ %s], %d symbols", start_str, end_str, len(universe)) + + def _daily_chunk(cur: int, tot: int) -> None: + emit("extend_history", 10 + int(35 * cur / tot), + f"日K 批次 {cur}/{tot}", stage_pct=int(100 * cur / tot), skip_log=True) + + written_daily = kline_sync.sync_and_persist_daily_batch( + universe, repo, capset, + start_date=datetime.combine(new_start, datetime.min.time()), + end_date=datetime.combine(earliest, datetime.min.time()), + on_chunk_done=_daily_chunk, + ) + emit("extend_history", 45, f"日K 完成,写入 {written_daily} 行") + logger.info("extend_history: daily K done, %d rows", written_daily) + _refresh_single_view(repo, "kline_daily") + _invalidate("daily") + + # 4. 拉除权因子 (新范围) + written_adj = 0 + adj_start = datetime.combine(new_start, datetime.min.time()) + adj_end = datetime.combine(today, datetime.min.time()) + adj_start_str = new_start.strftime("%Y-%m-%d") + adj_end_str = today.strftime("%Y-%m-%d") + + if capset.has(Cap.ADJ_FACTOR): + emit("extend_history", 48, f"获取除权因子 [{adj_start_str} ~ {adj_end_str}]…") + logger.info("extend_history: adj_factor [%s ~ %s]", adj_start_str, adj_end_str) + + def _adj_chunk(cur: int, tot: int) -> None: + emit("extend_history", 48 + int(10 * cur / tot), + f"除权因子批次 {cur}/{tot}", stage_pct=int(100 * cur / tot), skip_log=True) + + written_adj, _affected = kline_sync.sync_adj_factor( + universe, repo, capset, + start_time=adj_start, end_time=adj_end, + on_chunk_done=_adj_chunk, + ) + emit("extend_history", 60, f"除权因子完成,{written_adj} 行") + logger.info("extend_history: adj_factor done, %d rows", written_adj) + _refresh_single_view(repo, "adj_factor") + _invalidate("adj_factor") + else: + emit("extend_history", 60, "除权因子跳过(无权限)") + logger.info("extend_history: adj_factor skipped, no ADJ_FACTOR capability") + + # 5. 全量重算 enriched + emit("extend_history", 65, "全量计算 enriched…") + logger.info("extend_history: full enriched rebuild start") + + from app.indicators.pipeline import run_pipeline + written_enriched = run_pipeline() + + enriched_dir = repo.store.data_dir / "kline_daily_enriched" + enriched_days = len(list(enriched_dir.glob("date=*"))) if enriched_dir.exists() else 0 + emit("extend_history", 92, f"enriched 完成,覆盖 {enriched_days} 天") + logger.info("extend_history: enriched done, %d days", enriched_days) + _refresh_single_view(repo, "kline_enriched") + _invalidate("enriched") + + # 6. 刷新视图 + emit("extend_history", 95, "刷新视图…") + _refresh_single_view(repo, "kline_daily") + _refresh_single_view(repo, "kline_enriched") + _refresh_single_view(repo, "adj_factor") + _invalidate(None) + + # 7. 统计结果 + daily_dir = repo.store.data_dir / "kline_daily" + daily_days = len(list(daily_dir.glob("date=*"))) if daily_dir.exists() else 0 + + emit("extend_history", 100, f"完成,已扩展至 {new_start}") + + return { + "earliest_before": earliest.isoformat(), + "earliest_after": new_start.isoformat(), + "daily_rows": written_daily, + "daily_days": daily_days, + "adj_factor_rows": written_adj, + "enriched_days": enriched_days, + "universe_size": len(universe), + } diff --git a/backend/app/services/financial_sync.py b/backend/app/services/financial_sync.py new file mode 100644 index 0000000..da19ed1 --- /dev/null +++ b/backend/app/services/financial_sync.py @@ -0,0 +1,273 @@ +"""财务数据独立同步服务。 + +解耦于 K-line 管道, 自有调度 + 自有存储。 +能力门控: Cap.FINANCIAL (Expert 套餐) +""" +from __future__ import annotations + +import asyncio +import logging +import threading +from datetime import date, datetime, timezone +from pathlib import Path +from typing import Any + +import polars as pl + +from app.tickflow.capabilities import Cap, CapabilitySet + +logger = logging.getLogger(__name__) + +# 每个 API 请求最多 100 个标的 +_BATCH_SIZE = 100 + +# 4 张财务表 +FINANCIAL_TABLES = ("metrics", "income", "balance_sheet", "cash_flow") + + +# ================================================================ +# 同步函数 +# ================================================================ + +def _get_symbols(data_dir: Path) -> list[str]: + """从 instruments 表获取标的列表。""" + inst_path = data_dir / "instruments" / "instruments.parquet" + if not inst_path.exists(): + return [] + try: + df = pl.read_parquet(inst_path, columns=["symbol"]) + return df["symbol"].to_list() + except Exception as e: + logger.warning("读取 instruments 失败: %s", e) + return [] + + +def _sync_table( + table: str, + symbols: list[str], + data_dir: Path, + capset: CapabilitySet, + latest_only: bool = True, +) -> int: + """同步单张财务表。返回写入的行数。""" + if not capset.has(Cap.FINANCIAL): + logger.info("sync_%s skipped: no FINANCIAL capability", table) + return 0 + if not symbols: + logger.warning("sync_%s skipped: no symbols", table) + return 0 + + from app.tickflow.client import get_client + tf = get_client() + + # 分批拉取 + api_method = { + "metrics": tf.financials.metrics, + "income": tf.financials.income, + "balance_sheet": tf.financials.balance_sheet, + "cash_flow": tf.financials.cash_flow, + }[table] + + all_records: list[dict] = [] + total_batches = (len(symbols) + _BATCH_SIZE - 1) // _BATCH_SIZE + + for i in range(0, len(symbols), _BATCH_SIZE): + chunk = symbols[i : i + _BATCH_SIZE] + batch_num = i // _BATCH_SIZE + 1 + try: + data = api_method(chunk, latest=latest_only) + # data 格式: { "600519.SH": [record, ...], ... } + if isinstance(data, dict): + for sym, records in data.items(): + if isinstance(records, list): + for rec in records: + if isinstance(rec, dict): + rec["symbol"] = sym + all_records.append(rec) + logger.debug("sync_%s batch %d/%d: %d records", table, batch_num, total_batches, len(data) if isinstance(data, dict) else 0) + except Exception as e: + logger.warning("sync_%s batch %d/%d failed: %s", table, batch_num, total_batches, e) + + if not all_records: + return 0 + + df = pl.DataFrame(all_records) + if df.is_empty(): + return 0 + + # 确保 symbol 列存在 + if "symbol" not in df.columns: + return 0 + + # 写入 Parquet (全量覆盖) + out_dir = data_dir / "financials" / table + out_dir.mkdir(parents=True, exist_ok=True) + out_file = out_dir / "part.parquet" + df.write_parquet(out_file) + + logger.info("sync_%s done: %d records written", table, len(df)) + return len(df) + + +def sync_metrics(data_dir: Path, capset: CapabilitySet) -> int: + """同步核心财务指标 (metrics)。""" + symbols = _get_symbols(data_dir) + return _sync_table("metrics", symbols, data_dir, capset, latest_only=True) + + +def sync_income(data_dir: Path, capset: CapabilitySet) -> int: + """同步利润表。""" + symbols = _get_symbols(data_dir) + return _sync_table("income", symbols, data_dir, capset, latest_only=True) + + +def sync_balance_sheet(data_dir: Path, capset: CapabilitySet) -> int: + """同步资产负债表。""" + symbols = _get_symbols(data_dir) + return _sync_table("balance_sheet", symbols, data_dir, capset, latest_only=True) + + +def sync_cash_flow(data_dir: Path, capset: CapabilitySet) -> int: + """同步现金流量表。""" + symbols = _get_symbols(data_dir) + return _sync_table("cash_flow", symbols, data_dir, capset, latest_only=True) + + +def sync_all(data_dir: Path, capset: CapabilitySet) -> dict[str, int]: + """同步所有财务表。返回 {table: rows}。""" + if not capset.has(Cap.FINANCIAL): + logger.info("sync_all financials skipped: no FINANCIAL capability") + return {} + + symbols = _get_symbols(data_dir) + results: dict[str, int] = {} + for table in FINANCIAL_TABLES: + results[table] = _sync_table(table, symbols, data_dir, capset, latest_only=True) + + # 同步完成后注册 DuckDB 视图 + _refresh_financials_views(data_dir) + + return results + + +# ================================================================ +# DuckDB 视图 +# ================================================================ + +def _refresh_financials_views(data_dir: Path) -> None: + """刷新财务表 DuckDB 视图 (在 DataStore.db 上注册)。""" + d = data_dir.as_posix() + views = { + "financials_metrics": f"{d}/financials/metrics/*.parquet", + "financials_income": f"{d}/financials/income/*.parquet", + "financials_balance_sheet": f"{d}/financials/balance_sheet/*.parquet", + "financials_cash_flow": f"{d}/financials/cash_flow/*.parquet", + } + for name, path in views.items(): + out = data_dir / "financials" / name.replace("financials_", "") / "part.parquet" + if not out.exists(): + continue + # 视图注册需要由 DataStore 完成,这里只做日志 + logger.debug("financial parquet ready: %s (%d rows)", name, out.stat().st_size) + + +def get_financial_df(data_dir: Path, table: str) -> pl.DataFrame: + """读取本地财务 Parquet。""" + path = data_dir / "financials" / table / "part.parquet" + if not path.exists(): + return pl.DataFrame() + try: + return pl.read_parquet(path) + except Exception as e: + logger.warning("读取 financials/%s 失败: %s", table, e) + return pl.DataFrame() + + +# ================================================================ +# 调度器 +# ================================================================ + +class FinancialScheduler: + """独立调度器: 每周同步 metrics, 每季度同步三张报表。""" + + def __init__(self) -> None: + self._task: asyncio.Task | None = None + self._running = False + self._data_dir: Path | None = None + self._capset: CapabilitySet | None = None + self._lock = threading.Lock() + self._last_sync: dict[str, str] = {} # {table: iso_timestamp} + + def start(self, data_dir: Path, capset: CapabilitySet) -> None: + if not capset.has(Cap.FINANCIAL): + logger.info("FinancialScheduler skipped: no FINANCIAL capability") + return + self._data_dir = data_dir + self._capset = capset + self._running = True + self._task = asyncio.create_task(self._run_loop()) + logger.info("FinancialScheduler started") + + def stop(self) -> None: + self._running = False + if self._task: + self._task.cancel() + self._task = None + logger.info("FinancialScheduler stopped") + + async def _run_loop(self) -> None: + """每周执行一次 metrics 同步。""" + try: + while self._running: + # 首次启动等 60s, 之后每 7 天执行一次 + await asyncio.sleep(60) + if not self._running: + break + + # 每周: 只同步 metrics + try: + rows = sync_metrics(self._data_dir, self._capset) + self._last_sync["metrics"] = datetime.now(timezone.utc).isoformat() + logger.info("FinancialScheduler: metrics synced, %d rows", rows) + except Exception as e: + logger.warning("FinancialScheduler: metrics sync failed: %s", e) + + # 等待下一次 (7天) + for _ in range(7 * 24 * 60): # 每分钟检查一次 _running + if not self._running: + break + await asyncio.sleep(60) + + except asyncio.CancelledError: + pass + + def run_now(self, table: str | None = None) -> dict[str, int]: + """手动触发同步。table=None 同步全部。""" + if not self._capset or not self._capset.has(Cap.FINANCIAL): + return {} + if table: + fn = { + "metrics": sync_metrics, + "income": sync_income, + "balance_sheet": sync_balance_sheet, + "cash_flow": sync_cash_flow, + }.get(table) + if not fn: + return {} + rows = fn(self._data_dir, self._capset) + self._last_sync[table] = datetime.now(timezone.utc).isoformat() + return {table: rows} + else: + result = sync_all(self._data_dir, self._capset) + now = datetime.now(timezone.utc).isoformat() + for t in result: + self._last_sync[t] = now + return result + + @property + def last_sync(self) -> dict[str, str]: + return dict(self._last_sync) + + +# 全局单例 +financial_scheduler = FinancialScheduler() diff --git a/backend/app/services/index_sync.py b/backend/app/services/index_sync.py new file mode 100644 index 0000000..b7ee11a --- /dev/null +++ b/backend/app/services/index_sync.py @@ -0,0 +1,146 @@ +"""指数数据同步服务。""" +from __future__ import annotations + +import logging +import gc +from datetime import datetime, timedelta + +import polars as pl + +from app.indicators.pipeline import compute_enriched +from app.services import kline_sync, preferences +from app.tickflow.capabilities import Cap, CapabilitySet +from app.tickflow.client import get_client +from app.tickflow.repository import KlineRepository + +logger = logging.getLogger(__name__) + + +def _quotes_to_index_instruments(resp) -> pl.DataFrame: + """将 TickFlow quotes 响应规范为指数 instruments。""" + if resp is None: + return pl.DataFrame() + + if isinstance(resp, pl.DataFrame): + df = resp + elif hasattr(resp, "columns"): + df = pl.from_pandas(resp.reset_index() if hasattr(resp, "reset_index") else resp) + else: + rows: list[dict] = [] + for q in resp or []: + item = q if isinstance(q, dict) else {} + ext = item.get("ext") or {} + symbol = item.get("symbol") + if not symbol: + continue + rows.append({ + "symbol": str(symbol), + "name": ext.get("name") or item.get("name") or str(symbol), + }) + df = pl.DataFrame(rows) + + if df.is_empty() or "symbol" not in df.columns: + return pl.DataFrame() + + rename = {"ts_code": "symbol"} + df = df.rename({k: v for k, v in rename.items() if k in df.columns}) + + if "name" not in df.columns: + if "ext" in df.columns: + df = df.with_columns(pl.col("symbol").cast(pl.Utf8).alias("name")) + else: + df = df.with_columns(pl.col("symbol").cast(pl.Utf8).alias("name")) + + result = df.select([ + pl.col("symbol").cast(pl.Utf8), + pl.col("name").cast(pl.Utf8), + ]).with_columns([ + pl.col("symbol").str.split(".").list.first().alias("code"), + pl.lit("index").alias("asset_type"), + ]) + return result.unique(subset=["symbol"], keep="last").sort("symbol") + + +def sync_index_instruments(repo: KlineRepository) -> int: + """同步 CN_Index 指数标的维表,返回指数数量。""" + tf = get_client() + resp = None + errors: list[str] = [] + for kwargs in ( + {"universes": ["CN_Index"]}, + {"universes": ["CN_Index"], "as_dataframe": False}, + ): + try: + resp = tf.quotes.get_by_universes(**kwargs) + if resp is not None and len(resp) > 0: + break + except Exception as e: # noqa: BLE001 + errors.append(str(e)) + resp = None + + if resp is None or len(resp) == 0: + logger.warning("CN_Index universe returned empty: %s", "; ".join(errors)) + return 0 + + instruments = _quotes_to_index_instruments(resp) + if instruments.is_empty(): + return 0 + repo.save_index_instruments(instruments) + repo.refresh_index_views() + return instruments.height + + +def sync_and_persist_index_daily( + repo: KlineRepository, + capset: CapabilitySet, + count: int | None = None, + start_date: datetime | None = None, + end_date: datetime | None = None, +) -> int: + """同步指数日K到独立 parquet,并计算指数 enriched。""" + if not capset.has(Cap.KLINE_DAILY_BATCH): + return 0 + + instruments = repo.get_index_instruments() + if instruments.is_empty(): + sync_index_instruments(repo) + instruments = repo.get_index_instruments() + if instruments.is_empty() or "symbol" not in instruments.columns: + return 0 + + symbols = sorted(set(instruments["symbol"].to_list())) + lim = capset.limits(Cap.KLINE_DAILY_BATCH) + batch_size = preferences.get_index_daily_batch_size() + if lim and lim.batch: + batch_size = min(batch_size, lim.batch) + rpm = lim.rpm if lim else None + + end_time = end_date or datetime.now() + start_time = start_date or (end_time - timedelta(days=365)) + + total_rows = 0 + interval = (60.0 / rpm) if rpm else 0 + chunks = [symbols[i:i + batch_size] for i in range(0, len(symbols), batch_size)] + for i, chunk in enumerate(chunks): + if i > 0 and interval > 0 and len(chunks) > rpm: + import time + time.sleep(interval) + raw = kline_sync.sync_daily_batch( + chunk, + count=count, + batch_size=None, + start_time=start_time, + end_time=end_time, + ) + if raw.is_empty(): + continue + + repo.append_index_daily(raw) + enriched = compute_enriched(raw, factors=None, instruments=None) + repo.append_index_enriched(enriched) + total_rows += raw.height + logger.info("index daily synced: %d/%d chunks, +%d rows", i + 1, len(chunks), raw.height) + del raw, enriched + gc.collect() + repo.refresh_index_views() + return total_rows diff --git a/backend/app/services/instrument_sync.py b/backend/app/services/instrument_sync.py new file mode 100644 index 0000000..2abae49 --- /dev/null +++ b/backend/app/services/instrument_sync.py @@ -0,0 +1,122 @@ +"""标的维表同步服务。 + +盘前 9:10 调用 tf.exchanges.get_instruments("SH"/"SZ"/"BJ", type="stock") +获取全量标的元数据,flatten ext 字段,写入 instruments.parquet。 + +Starter+ 盘后可用 quotes.get(universes) 顺便补充 name。 +""" +from __future__ import annotations + +import logging +from datetime import date +from pathlib import Path + +import polars as pl + +from app.tickflow.client import get_client + +logger = logging.getLogger(__name__) + +_EXCHANGES = ["SH", "SZ", "BJ"] + + +def _flatten_instruments(items: list[dict]) -> list[dict]: + """把 SDK 返回的 Instrument 列表 flatten 成扁平行。""" + rows = [] + for item in items: + row = { + "symbol": item.get("symbol"), + "name": item.get("name"), + "code": item.get("code"), + "exchange": item.get("exchange"), + "region": item.get("region"), + "type": item.get("type"), + } + ext = item.get("ext") or {} + row["listing_date"] = ext.get("listing_date") + row["total_shares"] = ext.get("total_shares") + row["float_shares"] = ext.get("float_shares") + row["tick_size"] = ext.get("tick_size") + row["limit_up"] = ext.get("limit_up") + row["limit_down"] = ext.get("limit_down") + rows.append(row) + return rows + + +def sync_instruments(data_dir: Path) -> int: + """全量同步标的维表 → data/instruments/instruments.parquet。 + + 返回写入的行数。 + """ + tf = get_client() + all_rows: list[dict] = [] + + for ex in _EXCHANGES: + try: + items = tf.exchanges.get_instruments(ex, instrument_type="stock") + if items: + all_rows.extend(_flatten_instruments(items)) + logger.info("instruments %s: %d stocks", ex, len(items)) + except Exception as e: + logger.warning("get_instruments(%s) failed: %s", ex, e) + + if not all_rows: + return 0 + + df = pl.DataFrame(all_rows) + df = df.with_columns(pl.lit(date.today()).alias("as_of")) + + out = data_dir / "instruments" / "instruments.parquet" + out.parent.mkdir(parents=True, exist_ok=True) + df.write_parquet(out) + + logger.info("instruments synced: %d rows → %s", df.height, out) + return df.height + + +def enrich_names_from_quotes( + data_dir: Path, + quotes_data: list[dict], +) -> int: + """从 quotes 响应中提取 name,更新 instruments 维表(兜底补充)。 + + 盘后 quotes.get(universes) 返回的数据中包含 ext.name, + 用来补充 instruments 中可能缺失的 name。 + """ + if not quotes_data: + return 0 + + # 构建 symbol → name 映射 + name_map: dict[str, str] = {} + for q in quotes_data: + symbol = q.get("symbol", "") + ext = q.get("ext") or {} + name = ext.get("name") or q.get("name", "") + if symbol and name: + name_map[symbol] = name + + if not name_map: + return 0 + + inst_path = data_dir / "instruments" / "instruments.parquet" + if not inst_path.exists(): + return 0 + + df = pl.read_parquet(inst_path) + + # 只更新空 name 的行 + updates = pl.DataFrame({ + "symbol": list(name_map.keys()), + "_new_name": list(name_map.values()), + }) + df = df.join(updates, on="symbol", how="left") + df = df.with_columns( + pl.when(pl.col("name").is_null() | (pl.col("name") == "")) + .then(pl.col("_new_name")) + .otherwise(pl.col("name")) + .alias("name"), + ).drop("_new_name") + + df.write_parquet(inst_path) + logger.info("instruments name enriched from quotes: %d names", len(name_map)) + return len(name_map) diff --git a/backend/app/services/kline_sync.py b/backend/app/services/kline_sync.py new file mode 100644 index 0000000..e1ac71d --- /dev/null +++ b/backend/app/services/kline_sync.py @@ -0,0 +1,617 @@ +"""日 K 同步服务(§7.7 Step 1)。 + +调度器在 capability 允许下,把符号集合的日 K 批量同步到本地 Parquet。 +策略: + - 日 K 仅使用 `kline.daily.batch` + - 除权因子仅使用 `adj_factor` +""" +from __future__ import annotations + +import logging +import time +from collections.abc import Callable +from datetime import datetime, timedelta + +import polars as pl + +from app.indicators.pipeline import filter_halt_days +from app.tickflow.capabilities import Cap, CapabilitySet +from app.tickflow.client import get_client +from app.tickflow.repository import KlineRepository + +logger = logging.getLogger(__name__) + + +# 标准列(无论 SDK 返回什么形状,我们把它规范成这套) +CANONICAL_DAILY_COLS = [ + "symbol", "date", "open", "high", "low", "close", "volume", "amount", +] + + +def _normalize_daily(df_in, default_symbol: str | None = None) -> pl.DataFrame: + """把 SDK 返回的 pandas/任意 DataFrame 规范成 canonical 列。""" + if df_in is None or len(df_in) == 0: + return pl.DataFrame() + + if not isinstance(df_in, pl.DataFrame): + df = pl.from_pandas(df_in.reset_index() if hasattr(df_in, "reset_index") else df_in) + else: + df = df_in + + # 兼容字段名差异 + rename_map = { + "ts_code": "symbol", + "trade_date": "date", + "vol": "volume", + "amt": "amount", + "datetime": "date", + } + df = df.rename({k: v for k, v in rename_map.items() if k in df.columns}) + + if "symbol" not in df.columns and default_symbol is not None: + df = df.with_columns(pl.lit(default_symbol).alias("symbol")) + + # 类型规范 + if "date" in df.columns and df.schema["date"] != pl.Date: + df = df.with_columns(pl.col("date").cast(pl.Date, strict=False)) + + for col in ("open", "high", "low", "close"): + if col in df.columns: + df = df.with_columns(pl.col(col).cast(pl.Float64, strict=False)) + for col in ("volume", "amount"): + if col in df.columns: + df = df.with_columns(pl.col(col).cast(pl.Float64, strict=False)) + + # 过滤停牌日 (open/high 为 0; close 可能被填充为前收盘价, 不能用全零判断) + df = filter_halt_days(df) + + # 只保留 canonical 列 + keep = [c for c in CANONICAL_DAILY_COLS if c in df.columns] + return df.select(keep) + + +def sync_daily_batch(symbols: list[str], + count: int | None = None, + batch_size: int | None = None, + rpm: int | None = None, + start_time: datetime | None = None, + end_time: datetime | None = None, + on_chunk_done: Callable[[int, int], None] | None = None) -> pl.DataFrame: + """批量拉取多股日 K。 + + 优先使用 start_time / end_time 区间 + count=10000,确保覆盖完整时间段。 + 仅传 count 时按条数回溯。 + """ + tf = get_client() + out: list[pl.DataFrame] = [] + interval = (60.0 / rpm) if rpm else 0 + + if batch_size is None: + chunks = [symbols] + else: + chunks = [symbols[i:i + batch_size] for i in range(0, len(symbols), batch_size)] + + for i, chunk in enumerate(chunks): + if i > 0 and interval > 0 and len(chunks) > rpm: + time.sleep(interval) + try: + if start_time and end_time: + raw = tf.klines.batch( + chunk, period="1d", adjust="none", + start_time=_datetime_to_ms(start_time), + end_time=_datetime_to_ms(end_time), + count=10000, + as_dataframe=True, show_progress=False, + ) + else: + raw = tf.klines.batch(chunk, period="1d", count=count or 250, adjust="none", + as_dataframe=True, show_progress=False) + except Exception as e: # noqa: BLE001 + logger.warning("batch fetch failed for %d symbols: %s", len(chunk), e) + continue + + # 兼容两种形态:dict[sym → df] 和扁平 df + if isinstance(raw, dict): + for sym, sub in raw.items(): + if sub is None or len(sub) == 0: + continue + out.append(_normalize_daily(sub, default_symbol=sym)) + elif raw is not None and len(raw) > 0: + out.append(_normalize_daily(raw)) + + if on_chunk_done: + on_chunk_done(i + 1, len(chunks)) + + if not out: + return pl.DataFrame() + return pl.concat(out, how="diagonal_relaxed") + + +def sync_and_persist_daily_batch( + symbols: list[str], + repo: KlineRepository, + capset: CapabilitySet, + count: int | None = None, + start_date: datetime | None = None, + end_date: datetime | None = None, + on_chunk_done: Callable[[int, int], None] | None = None, +) -> int: + """批量同步日 K 并落到 Parquet。返回写入的行数。 + + start_date/end_date: 外部传入的时间范围(由 pipeline 根据已有数据计算)。 + 未传入时默认拉最近 1 年。 + """ + if not symbols or not capset.has(Cap.KLINE_DAILY_BATCH): + return 0 + + lim = capset.limits(Cap.KLINE_DAILY_BATCH) + batch_size = lim.batch if lim and lim.batch else 100 + rpm = lim.rpm if lim else None + + end_time = end_date or datetime.now() + start_time = start_date or (end_time - timedelta(days=365)) + + df = sync_daily_batch( + symbols, count=count, batch_size=batch_size, rpm=rpm, + start_time=start_time, end_time=end_time, + on_chunk_done=on_chunk_done, + ) + + if df.is_empty(): + return 0 + + repo.append_daily(df) + + try: + d = repo.store.data_dir.as_posix() + repo.db.execute( + f"""CREATE OR REPLACE VIEW kline_daily AS + SELECT * FROM read_parquet('{d}/kline_daily/**/*.parquet', union_by_name=true)""" + ) + except Exception as e: # noqa: BLE001 + logger.warning("refresh view failed: %s", e) + + return df.height + + +def sync_daily_by_quotes(repo: KlineRepository) -> int: + """用实时行情接口拉全市场当日数据,覆写 kline_daily 今天分区。 + + 一个请求覆盖 ~5500 只股票,比 batch K-line 快几个数量级。 + 返回写入的行数。 + """ + from datetime import date as _date + + from app.tickflow.client import get_client + + tf = get_client() + try: + resp = tf.quotes.get_by_universes(universes=["CN_Equity_A"]) + except Exception as e: + logger.warning("get_by_universes failed: %s", e) + return 0 + + if not resp: + logger.warning("get_by_universes returned empty") + return 0 + + records = [] + for q in resp: + ext = q.get("ext") or {} + records.append({ + "symbol": q.get("symbol"), + "open": q.get("open"), + "high": q.get("high"), + "low": q.get("low"), + "close": q.get("last_price"), + "volume": q.get("volume"), + "amount": q.get("amount"), + }) + + df = pl.DataFrame(records) + if df.is_empty(): + return 0 + + today = _date.today() + daily_df = df.with_columns(pl.lit(today).cast(pl.Date).alias("date")) + + # 过滤停牌 (open/high 为 0; close 可能被填充为前收盘价, 不能用全零判断) + daily_df = filter_halt_days(daily_df) + + repo.flush_live_daily(daily_df) + logger.info("sync_daily_by_quotes: %d symbols flushed for %s", daily_df.height, today) + return daily_df.height + + +def sync_adj_factor(symbols: list[str], repo: KlineRepository, + capset: CapabilitySet, + start_time: datetime | None = None, + end_time: datetime | None = None, + on_chunk_done: Callable[[int, int], None] | None = None) -> tuple[int, list[str]]: + """同步除权因子(Starter+)。SDK 接口:`tf.klines.ex_factors(symbols=...)`。 + + 支持增量: 传 start_time/end_time 只拉取该时间范围内的新除权事件。 + 返回 (写入行数, 受影响的 symbol 列表) — 供 enriched 局部重算使用。 + """ + if not capset.has(Cap.ADJ_FACTOR) or not symbols: + return 0, [] + + tf = get_client() + lim = capset.limits(Cap.ADJ_FACTOR) + batch_size = lim.batch if lim and lim.batch else 50 + rpm = lim.rpm if lim else 30 + interval = 60.0 / rpm if rpm else 0 + + # 构建 SDK 参数 + sdk_kwargs: dict = {"as_dataframe": True, "batch_size": batch_size, "show_progress": False} + if start_time: + sdk_kwargs["start_time"] = _datetime_to_ms(start_time) + if end_time: + sdk_kwargs["end_time"] = _datetime_to_ms(end_time) + + chunks = [symbols[i:i + batch_size] for i in range(0, len(symbols), batch_size)] + all_dfs: list[pl.DataFrame] = [] + + for i, chunk in enumerate(chunks): + if i > 0 and interval > 0 and len(chunks) > rpm: + time.sleep(interval) + try: + raw = tf.klines.ex_factors(chunk, **sdk_kwargs) + if raw is not None and len(raw) > 0: + all_dfs.append(pl.from_pandas( + raw.reset_index() if hasattr(raw, "reset_index") else raw + )) + logger.debug("adj_factor chunk %d/%d: %d symbols", i + 1, len(chunks), len(chunk)) + except Exception as e: # noqa: BLE001 + logger.warning("adj_factor chunk %d failed: %s", i + 1, e) + + if on_chunk_done: + on_chunk_done(i + 1, len(chunks)) + + if not all_dfs: + return 0, [] + + new_data = pl.concat(all_dfs, how="diagonal_relaxed") if len(all_dfs) > 1 else all_dfs[0] + + # 提取受影响的 symbol 列表(合并前) + affected = new_data["symbol"].unique().to_list() + + out = repo.store.data_dir / "adj_factor" / "all.parquet" + out.parent.mkdir(parents=True, exist_ok=True) + + if out.exists(): + existing = pl.read_parquet(out) + before = existing.height + merged = pl.concat([existing, new_data]).unique( + subset=["symbol", "trade_date"], keep="last", + ).sort(["symbol", "trade_date"]) + merged.write_parquet(out) + added = merged.height - before + logger.info("adj_factor merged: %d total (+%d new), %d/%d symbols", + merged.height, added, new_data.height, len(symbols)) + return added, affected + else: + new_data.sort(["symbol", "trade_date"]).write_parquet(out) + logger.info("adj_factor synced: %d rows (%d symbols)", new_data.height, len(symbols)) + return new_data.height, affected + + +# ===== 分钟 K 同步 ===== + +CANONICAL_MINUTE_COLS = [ + "symbol", "datetime", "open", "high", "low", "close", "volume", "amount", +] + + +def _normalize_minute(df_in, default_symbol: str | None = None) -> pl.DataFrame: + """把 SDK 返回的分钟 K 数据规范成 canonical 列。""" + if df_in is None or len(df_in) == 0: + return pl.DataFrame() + + if not isinstance(df_in, pl.DataFrame): + df = pl.from_pandas(df_in.reset_index() if hasattr(df_in, "reset_index") else df_in) + else: + df = df_in + + rename_map = { + "ts_code": "symbol", + "vol": "volume", + "amt": "amount", + } + df = df.rename({k: v for k, v in rename_map.items() if k in df.columns}) + + # datetime 列:优先用 timestamp(毫秒精度),其次 trade_time + if "timestamp" in df.columns: + df = df.with_columns( + pl.from_epoch("timestamp", time_unit="ms").alias("datetime"), + ).drop("timestamp") + for drop_col in ("trade_time", "trade_date"): + if drop_col in df.columns: + df = df.drop(drop_col) + elif "trade_time" in df.columns: + df = df.rename({"trade_time": "datetime"}) + if "trade_date" in df.columns: + df = df.drop("trade_date") + elif "trade_date" in df.columns: + df = df.rename({"trade_date": "datetime"}) + + if "symbol" not in df.columns and default_symbol is not None: + df = df.with_columns(pl.lit(default_symbol).alias("symbol")) + + # 类型规范:统一转 Datetime('us') + if "datetime" in df.columns: + dt_type = df.schema["datetime"] + if not isinstance(dt_type, pl.Datetime) or dt_type.time_unit != "us": + df = df.with_columns(pl.col("datetime").cast(pl.Datetime("us"), strict=False)) + + for col in ("open", "high", "low", "close"): + if col in df.columns: + df = df.with_columns(pl.col(col).cast(pl.Float64, strict=False)) + for col in ("volume", "amount"): + if col in df.columns: + df = df.with_columns(pl.col(col).cast(pl.Float64, strict=False)) + + keep = [c for c in CANONICAL_MINUTE_COLS if c in df.columns] + return df.select(keep) + + +def _datetime_to_ms(dt: datetime) -> int: + """datetime → 毫秒时间戳 (供 SDK start_time / end_time 使用)。""" + return int(dt.timestamp() * 1000) + + +def sync_minute_batch( + symbols: list[str], + start_time: datetime | None = None, + end_time: datetime | None = None, + count: int | None = None, + batch_size: int | None = None, + rpm: int | None = None, + on_chunk_done: Callable[[int, int], None] | None = None, +) -> pl.DataFrame: + """批量拉取多股分钟 K。 + + 优先使用 start_time / end_time 区间, 确保所有标的覆盖同一时间段。 + count 仅作为 fallback 保留。 + on_chunk_done(current, total) 每个 chunk 完成后回调。 + """ + tf = get_client() + out: list[pl.DataFrame] = [] + interval = (60.0 / rpm) if rpm else 0 + + if batch_size is None: + chunks = [symbols] + else: + chunks = [symbols[i:i + batch_size] for i in range(0, len(symbols), batch_size)] + + for i, chunk in enumerate(chunks): + if i > 0 and interval > 0 and len(chunks) > rpm: + time.sleep(interval) + try: + if start_time and end_time: + raw = tf.klines.batch( + chunk, period="1m", + start_time=_datetime_to_ms(start_time), + end_time=_datetime_to_ms(end_time), + count=10000, + as_dataframe=True, show_progress=False, + ) + else: + raw = tf.klines.batch(chunk, period="1m", count=count or 1200, + as_dataframe=True, show_progress=False) + except Exception as e: # noqa: BLE001 + logger.warning("minute batch fetch failed for %d symbols: %s", len(chunk), e) + continue + + if isinstance(raw, dict): + for sym, sub in raw.items(): + if sub is None or len(sub) == 0: + continue + out.append(_normalize_minute(sub, default_symbol=sym)) + elif raw is not None and len(raw) > 0: + out.append(_normalize_minute(raw)) + + if on_chunk_done: + on_chunk_done(i + 1, len(chunks)) + + if not out: + return pl.DataFrame() + return pl.concat(out, how="diagonal_relaxed") + + +def fetch_minute_single(symbol: str, trade_date: date) -> pl.DataFrame: + """从 TickFlow 实时拉取单股单日分钟 K(不写入本地)。""" + from datetime import datetime + start_time = datetime(trade_date.year, trade_date.month, trade_date.day, 9, 25, 0) + end_time = datetime(trade_date.year, trade_date.month, trade_date.day, 15, 5, 0) + tf = get_client() + try: + raw = tf.klines.batch( + [symbol], period="1m", + start_time=_datetime_to_ms(start_time), + end_time=_datetime_to_ms(end_time), + count=10000, + as_dataframe=True, show_progress=False, + ) + except Exception as e: + logger.warning("fetch_minute_single(%s, %s) failed: %s", symbol, trade_date, e) + return pl.DataFrame() + + if isinstance(raw, dict): + sub = raw.get(symbol) + return _normalize_minute(sub) if sub is not None and len(sub) > 0 else pl.DataFrame() + if raw is not None and len(raw) > 0: + return _normalize_minute(raw) + return pl.DataFrame() + + +def _latest_minute_datetime(repo: KlineRepository) -> datetime | None: + """本地分钟 K 数据的最新时间。""" + try: + res = repo.execute_one("SELECT max(datetime) FROM kline_minute") + if res and res[0]: + d = res[0] + if isinstance(d, datetime): + return d + return datetime.fromisoformat(str(d)) + except Exception: # noqa: BLE001 + pass + return None + + +def _cleanup_null_datetime_minute(repo: KlineRepository) -> None: + """检测并清除 datetime 全为 null 的旧版分钟 K 数据(迁移用)。""" + minute_dir = repo.store.data_dir / "kline_minute" + if not minute_dir.exists(): + return + try: + row = repo.execute_one( + "SELECT count(*) AS total, count(datetime) AS non_null FROM kline_minute" + ) + if row and row[0] > 0 and (row[1] is None or row[1] == 0): + # 全部 datetime 为 null — 清除所有分钟 K parquet + n = 0 + for f in minute_dir.rglob("*.parquet"): + f.unlink() + n += 1 + logger.info("cleaned %d corrupted minute-K parquet files (null datetime)", n) + except Exception as e: # noqa: BLE001 + logger.debug("minute cleanup check failed: %s", e) + + +def _migrate_symbol_to_date_partition(repo: KlineRepository) -> None: + """将旧版 symbol= 分区迁移为 date= 分区。迁移完成后删除旧目录。""" + minute_dir = repo.store.data_dir / "kline_minute" + if not minute_dir.exists(): + return + + old_dirs = [d for d in minute_dir.iterdir() if d.is_dir() and d.name.startswith("symbol=")] + if not old_dirs: + return + + logger.info("migrating %d symbol-partitioned minute-K dirs to date partition…", len(old_dirs)) + + all_frames: list[pl.DataFrame] = [] + for sym_dir in old_dirs: + for pq in sym_dir.glob("*.parquet"): + try: + df = pl.read_parquet(pq) + if "datetime" in df.columns: + df = df.filter(pl.col("datetime").is_not_null()) + if not df.is_empty(): + all_frames.append(df) + except Exception: # noqa: BLE001 + pass + + if not all_frames: + # 数据全部不可用,直接删旧目录 + for d in old_dirs: + d.mkdir(parents=True, exist_ok=True) + for f in d.rglob("*"): + if f.is_file(): + f.unlink() + d.rmdir() + return + + combined = pl.concat(all_frames, how="diagonal_relaxed") + combined = combined.unique(subset=["symbol", "datetime"], keep="last") + + # 按日期写新分区 + combined = combined.with_columns(pl.col("datetime").dt.date().alias("_trade_date")) + for day_df in combined.partition_by("_trade_date"): + trade_date = day_df["_trade_date"][0] + out = minute_dir / f"date={trade_date}" / "part.parquet" + out.parent.mkdir(parents=True, exist_ok=True) + day_df = day_df.drop("_trade_date").sort("symbol", "datetime") + day_df.write_parquet(out) + + # 删旧目录 + for d in old_dirs: + for f in d.rglob("*"): + if f.is_file(): + f.unlink() + # 移除空目录 + try: + d.rmdir() + except OSError: + pass + + logger.info("minute-K migration done: %d rows migrated", combined.height) + + +def sync_and_persist_minute( + symbols: list[str], + repo: KlineRepository, + capset: CapabilitySet, + days: int = 5, + on_chunk_done: Callable[[int, int], None] | None = None, +) -> int: + """同步分钟 K 并存到 Parquet(仅 raw,不前复权)。返回写入行数。 + + 使用 start_time / end_time 区间拉取, 确保所有标的覆盖同一时间段。 + on_chunk_done(current, total) 每个 chunk 完成后回调。 + """ + if not symbols or not capset.has(Cap.KLINE_MINUTE_BATCH): + return 0 + + # 迁移:旧版 _normalize_minute 未转换 timestamp→datetime,导致全部 datetime 为 null + # 检测到后直接清除(这些数据无法使用) + _cleanup_null_datetime_minute(repo) + + # 迁移:旧版按 symbol= 分区转为 date= 分区 + _migrate_symbol_to_date_partition(repo) + + now = datetime.now() + + # 计算时间区间: 首次拉取回溯 N 天, 增量从最后数据时间开始 + last_dt = _latest_minute_datetime(repo) + if last_dt: + start_time = last_dt + else: + start_time = now - timedelta(days=days) + end_time = now + + lim = capset.limits(Cap.KLINE_MINUTE_BATCH) + batch_size = lim.batch if lim and lim.batch else 100 + rpm = lim.rpm if lim else 30 + + df = sync_minute_batch(symbols, start_time=start_time, end_time=end_time, + batch_size=batch_size, rpm=rpm, + on_chunk_done=on_chunk_done) + if df.is_empty(): + return 0 + + # 按日期分区写: data/kline_minute/date={YYYY-MM-DD}/part.parquet + df = df.with_columns( + pl.col("datetime").dt.date().alias("_trade_date") + ) + written = 0 + for day_df in df.partition_by("_trade_date"): + trade_date = day_df["_trade_date"][0] + out = repo.store.data_dir / "kline_minute" / f"date={trade_date}" / "part.parquet" + out.parent.mkdir(parents=True, exist_ok=True) + if out.exists(): + existing = pl.read_parquet(out) + if "datetime" in existing.columns: + existing = existing.filter(pl.col("datetime").is_not_null()) + day_df = pl.concat([existing, day_df.drop("_trade_date")]).unique( + subset=["symbol", "datetime"], keep="last", + ) + else: + day_df = day_df.drop("_trade_date") + day_df = day_df.sort("symbol", "datetime") + day_df.write_parquet(out) + written += day_df.height + + # 刷新视图 + try: + d = repo.store.data_dir.as_posix() + repo.db.execute( + f"""CREATE OR REPLACE VIEW kline_minute AS + SELECT * FROM read_parquet('{d}/kline_minute/**/*.parquet', union_by_name=true)""" + ) + except Exception as e: # noqa: BLE001 + logger.warning("refresh kline_minute view failed: %s", e) + + logger.info("minute K synced: %d rows (%d symbols)", written, len(symbols)) + return written diff --git a/backend/app/services/pipeline_jobs.py b/backend/app/services/pipeline_jobs.py new file mode 100644 index 0000000..979eddb --- /dev/null +++ b/backend/app/services/pipeline_jobs.py @@ -0,0 +1,250 @@ +"""异步盘后管道任务注册表 — 每个 job 独立 JSON 文件。 + +设计: + - job_store/ 文件夹,每个 job 一个 {id}.json,最多保留 max_jobs 个文件 + - running/pending 状态的 job 仅存内存(高频读写) + - succeeded/failed 后写入独立文件并从内存释放 + - 列表查询 = 内存中的活跃 job + 磁盘文件扫描,按时间排序 + - 单个查询 = 内存优先,没有则读磁盘 + - 创建新 job 前检查文件数量,>= max_jobs 时删除最老的文件 +""" +from __future__ import annotations + +import json +import logging +import os +import threading +import uuid +from datetime import datetime +from pathlib import Path +from typing import Any, Literal + +logger = logging.getLogger(__name__) + +JobStatus = Literal["pending", "running", "succeeded", "failed"] + + +def _default_store_dir() -> Path: + from app.config import settings + return settings.data_dir / "job_store" + + +_STORE_DIR = _default_store_dir() + + +class JobStore: + def __init__(self, max_jobs: int = 50, store_dir: Path = _STORE_DIR) -> None: + self._max_jobs = max_jobs + self._store_dir = store_dir + self._active_jobs: dict[str, dict[str, Any]] = {} # running/pending + self._active_id: str | None = None + self._lock = threading.Lock() + self._store_dir.mkdir(parents=True, exist_ok=True) + + # ===== persistence ===== + + def _write_file(self, job: dict[str, Any]) -> None: + """将终态 job 写入独立 JSON 文件。""" + path = self._store_dir / f"{job['id']}.json" + try: + path.write_text( + json.dumps(job, ensure_ascii=False, indent=None), + encoding="utf-8", + ) + except Exception: + logger.warning("failed to write job file %s", path) + + def _read_file(self, job_id: str) -> dict[str, Any] | None: + """从磁盘读取单个 job 文件。""" + path = self._store_dir / f"{job_id}.json" + if not path.exists(): + return None + try: + return json.loads(path.read_text("utf-8")) + except Exception: + logger.warning("failed to read job file %s", path) + return None + + def _delete_oldest(self) -> None: + """删除最老的 job 文件,保持文件数量 < max_jobs。""" + try: + files = sorted(self._store_dir.glob("*.json"), key=lambda f: f.stat().st_mtime) + except Exception: + return + while len(files) >= self._max_jobs: + oldest = files.pop(0) + try: + oldest.unlink() + except Exception: + logger.warning("failed to delete old job file %s", oldest) + + def _job_files_sorted(self) -> list[dict[str, Any]]: + """扫描磁盘上所有 job 文件,按 started_at 从新到旧排序。""" + jobs: list[dict[str, Any]] = [] + for f in self._store_dir.glob("*.json"): + try: + jobs.append(json.loads(f.read_text("utf-8"))) + except Exception: + continue + jobs.sort(key=lambda j: j.get("started_at") or "", reverse=True) + return jobs + + # ===== lifecycle ===== + + def create(self) -> str: + with self._lock: + if self._active_id and self._active_jobs.get(self._active_id, {}).get("status") == "running": + return self._active_id + + job_id = uuid.uuid4().hex[:10] + self._active_jobs[job_id] = { + "id": job_id, + "status": "pending", + "stage": "init", + "progress": 0, + "stage_pct": 0, + "log": [], + "started_at": None, + "finished_at": None, + "duration_s": None, + "result": None, + "error": None, + } + self._active_id = job_id + return job_id + + def start(self, job_id: str) -> None: + with self._lock: + j = self._active_jobs.get(job_id) + if not j: + return + j["status"] = "running" + j["started_at"] = datetime.utcnow().isoformat(timespec="seconds") + "Z" + + def succeed(self, job_id: str, result: Any) -> None: + with self._lock: + j = self._active_jobs.pop(job_id, None) + if not j: + return + j["status"] = "succeeded" + j["finished_at"] = datetime.utcnow().isoformat(timespec="seconds") + "Z" + j["progress"] = 100 + j["result"] = result + j["duration_s"] = _duration_s(j) + if self._active_id == job_id: + self._active_id = None + self._delete_oldest() + self._write_file(j) + + def fail(self, job_id: str, error: str) -> None: + with self._lock: + j = self._active_jobs.pop(job_id, None) + if not j: + return + j["status"] = "failed" + j["finished_at"] = datetime.utcnow().isoformat(timespec="seconds") + "Z" + j["error"] = error + j["duration_s"] = _duration_s(j) + if self._active_id == job_id: + self._active_id = None + self._delete_oldest() + self._write_file(j) + + # ===== progress ===== + + def progress(self, job_id: str, stage: str, pct: int, msg: str, + stage_pct: int | None = None, skip_log: bool = False) -> None: + with self._lock: + j = self._active_jobs.get(job_id) + if not j: + return + j["stage"] = stage + j["progress"] = max(0, min(100, int(pct))) + if stage_pct is not None: + j["stage_pct"] = max(0, min(100, int(stage_pct))) + elif j["stage"] != stage: + j["stage_pct"] = 0 + entry = { + "ts": datetime.utcnow().isoformat(timespec="seconds") + "Z", + "stage": stage, + "msg": msg, + } + if skip_log: + entry["_skip"] = True + if skip_log and j["log"] and j["log"][-1].get("stage") == stage and j["log"][-1].get("_skip"): + j["log"][-1] = entry + else: + j["log"].append(entry) + if len(j["log"]) > 200: + j["log"] = j["log"][-200:] + + # ===== query ===== + + def get(self, job_id: str) -> dict[str, Any] | None: + # 内存中的活跃 job 优先 + j = self._active_jobs.get(job_id) + if j: + return j + # 否则从磁盘读 + return self._read_file(job_id) + + def list_recent(self, limit: int = 20) -> list[dict[str, Any]]: + # 合并: 内存中的活跃 job + 磁盘文件 + all_jobs: list[dict[str, Any]] = list(self._active_jobs.values()) + all_jobs.extend(self._job_files_sorted()) + # 按 started_at 从新到旧排序,去重(理论上不会有重复) + seen: set[str] = set() + result: list[dict[str, Any]] = [] + for j in sorted(all_jobs, key=lambda x: x.get("started_at") or "", reverse=True): + jid = j["id"] + if jid in seen: + continue + seen.add(jid) + result.append(_summary(j)) + if len(result) >= limit: + break + return result + + def active_id(self) -> str | None: + return self._active_id + + def clear(self) -> None: + """清空所有任务(内存 + 磁盘文件)。""" + with self._lock: + self._active_jobs.clear() + self._active_id = None + for f in self._store_dir.glob("*.json"): + try: + f.unlink() + except Exception: + pass + + +def _summary(j: dict[str, Any]) -> dict[str, Any]: + return { + "id": j["id"], + "status": j["status"], + "stage": j["stage"], + "progress": j["progress"], + "stage_pct": j.get("stage_pct", 0), + "started_at": j["started_at"], + "finished_at": j["finished_at"], + "duration_s": j["duration_s"], + "result": j["result"], + "error": j["error"], + } + + +def _duration_s(j: dict[str, Any]) -> float | None: + if not j.get("started_at") or not j.get("finished_at"): + return None + try: + s = datetime.fromisoformat(j["started_at"]) + e = datetime.fromisoformat(j["finished_at"]) + return round((e - s).total_seconds(), 2) + except Exception: # noqa: BLE001 + return None + + +# 进程内单例 +job_store = JobStore() diff --git a/backend/app/services/preferences.py b/backend/app/services/preferences.py new file mode 100644 index 0000000..29b1714 --- /dev/null +++ b/backend/app/services/preferences.py @@ -0,0 +1,250 @@ +"""用户偏好设置持久化。 + +存储位置: data/user_data/preferences.json +沿用 secrets_store 的 merge-write 模式,但不做 chmod 0600 (非敏感数据)。 +""" +from __future__ import annotations + +import json +import logging +from pathlib import Path + +logger = logging.getLogger(__name__) + + +def _path() -> Path: + from app.config import settings + p = settings.data_dir / "user_data" / "preferences.json" + p.parent.mkdir(parents=True, exist_ok=True) + return p + + +def load() -> dict: + p = _path() + if p.exists(): + try: + return json.loads(p.read_text(encoding="utf-8")) + except Exception as e: # noqa: BLE001 + logger.warning("preferences.json malformed: %s", e) + return {} + + +def save(updates: dict) -> dict: + """合并写入。返回新内容。""" + current = load() + current.update(updates) + _path().write_text( + json.dumps(current, indent=2, ensure_ascii=False), encoding="utf-8", + ) + return current + + +def get_realtime_quotes_enabled() -> bool: + return load().get("realtime_quotes_enabled", False) + + +def get_indices_nav_pinned() -> bool: + """侧栏指数报价卡片是否固定显示。默认 True(常驻)。 + 关闭后,卡片跟随实时行情开关(仅实时开时显示)。""" + return load().get("indices_nav_pinned", True) + + +def get_realtime_quote_interval() -> float: + return load().get("realtime_quote_interval", 10.0) + + +def set_realtime_quote_interval(interval: float) -> float: + """保存行情轮询间隔(不在此做 min/max 校验,由调用方按档位限制)。""" + current = load() + current["realtime_quote_interval"] = interval + _path().write_text( + json.dumps(current, indent=2, ensure_ascii=False), encoding="utf-8", + ) + return interval + + +def get_minute_sync_enabled() -> bool: + return load().get("minute_sync_enabled", False) + + +def get_minute_sync_days() -> int: + return max(1, min(30, load().get("minute_sync_days", 5))) + + +def get_pipeline_schedule() -> dict: + """返回盘后管道调度时间 {"hour": 15, "minute": 30}。""" + d = load().get("pipeline_schedule", {"hour": 15, "minute": 30}) + return {"hour": d.get("hour", 15), "minute": d.get("minute", 30)} + + +def set_pipeline_schedule(hour: int, minute: int) -> dict: + h = max(0, min(23, hour)) + m = max(0, min(59, minute)) + # 盘后不早于 15:00 + if h * 60 + m < 15 * 60: + h, m = 15, 0 + save({"pipeline_schedule": {"hour": h, "minute": m}}) + return {"hour": h, "minute": m} + + +def get_instruments_schedule() -> dict: + """返回盘前标的维表调度时间 {"hour": 9, "minute": 10}。""" + d = load().get("instruments_schedule", {"hour": 9, "minute": 10}) + return {"hour": d.get("hour", 9), "minute": d.get("minute", 10)} + + +def set_instruments_schedule(hour: int, minute: int) -> dict: + h = max(0, min(23, hour)) + m = max(0, min(59, minute)) + # 盘前不晚于 09:15 + if h * 60 + m > 9 * 60 + 15: + h, m = 9, 15 + save({"instruments_schedule": {"hour": h, "minute": m}}) + return {"hour": h, "minute": m} + + +def get_enriched_batch_size() -> int: + """返回 enriched 全量计算每批 symbol 数量。""" + return max(1, min(10000, load().get("enriched_batch_size", 1000))) + + +def set_enriched_batch_size(size: int) -> int: + """保存 enriched 全量计算批次大小。""" + size = max(10, min(6000, size)) + save({"enriched_batch_size": size}) + return size + + +def get_index_daily_batch_size() -> int: + """返回指数日 K 同步每批 symbol 数量。""" + return max(1, min(10000, load().get("index_daily_batch_size", 100))) + + +def set_index_daily_batch_size(size: int) -> int: + """保存指数日 K 同步批次大小。""" + size = max(1, min(10000, size)) + save({"index_daily_batch_size": size}) + return size + + +# ===== 实时监控 ===== + +# 页面 SSE 刷新配置: { "watchlist": true, "monitor": true, ... } +# 可刷新的页面列表及其默认值 +SSE_REFRESH_PAGES_DEFAULT = { + "watchlist": True, + "limit-ladder": False, +} + +SIDEBAR_INDEX_SYMBOLS_DEFAULT = ["000001.SH", "399001.SZ", "399006.SZ", "000680.SH"] + + +def get_sse_refresh_pages() -> dict[str, bool]: + """返回每个页面的 SSE 刷新开关。""" + stored = load().get("sse_refresh_pages", {}) + # 合并默认值 (新增页面自动出现) + result = dict(SSE_REFRESH_PAGES_DEFAULT) + result.update(stored) + return result + + +def set_sse_refresh_pages(pages: dict[str, bool]) -> dict[str, bool]: + """保存页面 SSE 刷新配置。""" + save({"sse_refresh_pages": pages}) + return get_sse_refresh_pages() + + +def get_sidebar_index_symbols() -> list[str]: + """返回左侧菜单显示的指数代码。""" + stored = load().get("sidebar_index_symbols", SIDEBAR_INDEX_SYMBOLS_DEFAULT) + allowed = set(SIDEBAR_INDEX_SYMBOLS_DEFAULT) + return [s for s in stored if s in allowed] + + +def get_strategy_monitor_enabled() -> bool: + """策略告警评估总开关。""" + return load().get("strategy_monitor_enabled", False) + + +def get_screener_auto_run() -> bool: + """选股页进入时是否自动运行所有策略 (获取命中数)。默认开。""" + return load().get("screener_auto_run", True) + + +def get_strategy_monitor_ids() -> list[str]: + """返回监控池中的策略 ID。""" + return load().get("strategy_monitor_ids", []) + + +def set_realtime_monitor_config(cfg: dict) -> dict: + """批量更新实时监控配置。""" + updates = {} + if "sse_refresh_pages" in cfg: + updates["sse_refresh_pages"] = cfg["sse_refresh_pages"] + if "strategy_monitor_enabled" in cfg: + updates["strategy_monitor_enabled"] = cfg["strategy_monitor_enabled"] + if "strategy_monitor_ids" in cfg: + updates["strategy_monitor_ids"] = cfg["strategy_monitor_ids"] + if "sidebar_index_symbols" in cfg: + allowed = set(SIDEBAR_INDEX_SYMBOLS_DEFAULT) + updates["sidebar_index_symbols"] = [s for s in cfg["sidebar_index_symbols"] if s in allowed] + if "screener_auto_run" in cfg: + updates["screener_auto_run"] = bool(cfg["screener_auto_run"]) + if updates: + save(updates) + return get_realtime_monitor_config() + + +def get_realtime_monitor_config() -> dict: + """返回完整的实时监控配置。""" + return { + "sse_refresh_pages": get_sse_refresh_pages(), + "strategy_monitor_enabled": get_strategy_monitor_enabled(), + "strategy_monitor_ids": get_strategy_monitor_ids(), + "sidebar_index_symbols": get_sidebar_index_symbols(), + "screener_auto_run": get_screener_auto_run(), + } + + +def get_nav_order() -> list[str]: + """返回左侧菜单的自定义排序(内置页面 path + 扩展分析菜单 id)。""" + return load().get("nav_order", []) + + +def set_nav_order(order: list[str]) -> list[str]: + """保存左侧菜单排序。""" + save({"nav_order": order}) + return get_nav_order() + + +def get_nav_hidden() -> list[str]: + """返回左侧菜单中隐藏的项 id 列表。""" + return load().get("nav_hidden", []) + + +def set_nav_hidden(hidden: list[str]) -> list[str]: + """保存左侧菜单隐藏项。""" + save({"nav_hidden": hidden}) + return get_nav_hidden() + + +def get_watchlist_columns() -> list[dict] | None: + """返回自选列表列配置。""" + return load().get("watchlist_columns") + + +def set_watchlist_columns(columns: list[dict]) -> list[dict]: + """保存自选列表列配置。""" + save({"watchlist_columns": columns}) + return columns + + +def get_screener_result_columns() -> list[dict] | None: + """返回策略结果列表列配置。""" + return load().get("screener_result_columns") + + +def set_screener_result_columns(columns: list[dict]) -> list[dict]: + """保存策略结果列表列配置。""" + save({"screener_result_columns": columns}) + return columns diff --git a/backend/app/services/quote_service.py b/backend/app/services/quote_service.py new file mode 100644 index 0000000..8d0e731 --- /dev/null +++ b/backend/app/services/quote_service.py @@ -0,0 +1,673 @@ +"""全局实时行情服务。 + +集中管理全市场行情拉取 + enriched 缓存,供盘中选股、自选股等所有模块复用。 + +架构: + - 后台线程轮询 TickFlow get_by_universes(["CN_Equity_A", "CN_Index"]) + - 拉取行情 → 写 kline_daily (不复权) + 增量计算 enriched → 写盘 + 更新缓存 + - _enriched_cache 是唯一的盘中数据源 (OHLCV + 全套技术指标) + - _live_agg_cache 是递推状态 (只加载一次, 盘中不变) + +数据流 (每轮 ~15s): + 1. API 拉取 → raw_records (临时变量) + 2. raw_records → 写 kline_daily (不复权原始价格) + 3. raw_records → 更新 _enriched_cache 的 OHLCV + 4. 增量计算 enriched 指标 (~50ms) + 5. 写 kline_daily_enriched + 替换 _enriched_cache + 6. 通知 SSE + +生命周期: + - 服务启动时读取 preferences,若 enabled 则自动启动线程 + - 运行中可通过 API 切换开关 + - 关闭时停止线程 +""" +from __future__ import annotations + +import logging +import threading +import time +from datetime import date, datetime, time as dt_time + +import polars as pl + +logger = logging.getLogger(__name__) + + +class QuoteService: + """全局实时行情服务 — 单例。""" + + CORE_INDEX_SYMBOLS = ("000001.SH", "399001.SZ", "399006.SZ", "000680.SH") + + # 档位 → 最小轮询间隔 (秒) + TIER_MIN_INTERVAL = { + "expert": 0.5, + "pro": 1.0, + "starter": 3.0, + } + DEFAULT_INTERVAL = 10.0 + MAX_INTERVAL = 60.0 + + def __init__(self) -> None: + self._lock = threading.Lock() + self._running = False + self._enabled = False # 全局开关 (持久化到 preferences) + self._interval = self.DEFAULT_INTERVAL + self._thread: threading.Thread | None = None + self._repo = None # 延迟注入, 避免循环导入 + self._update_event = threading.Event() # SSE 通知: 行情更新后 set + self._alert_event = threading.Event() # SSE 通知: 有告警时 set + self._pending_alerts: list[dict] = [] # 待推送的告警 + self._strategy_monitor = None # 延迟注入 + self._app_state = None # 延迟注入 (FastAPI app.state) + + # 拉取元信息 (给 SSE / status 用) + self._fetch_time: float = 0.0 # perf_counter (用于计算 quote_age_ms) + self._fetch_ms: float = 0.0 # 拉取耗时 (毫秒) + self._fetched_at: float = 0.0 # 拉取完成的 Unix 时间戳 (毫秒) + self._symbol_count: int = 0 + self._index_symbol_count: int = 0 + self._index_quotes_cache: pl.DataFrame | None = None + + # ================================================================ + # 生命周期 + # ================================================================ + + def start(self, interval: float = 0.0) -> None: + """启动后台行情轮询线程。""" + if self._running: + return + if interval <= 0: + from app.services import preferences + interval = preferences.get_realtime_quote_interval() + self._interval = self._clamp_interval(interval) + self._running = True + self._enabled = True + self._thread = threading.Thread(target=self._poll_loop, daemon=True) + self._thread.start() + self._save_enabled(True) + logger.info("行情服务已启动, 轮询间隔 %.1fs", self._interval) + + def stop(self) -> None: + """停止后台行情轮询线程。""" + self._running = False + self._enabled = False + if self._thread: + self._thread.join(timeout=10) + self._thread = None + self._save_enabled(False) + logger.info("行情服务已停止") + + def enable(self) -> None: + """开启自动行情 (不立即启动线程,等下一个交易时段)。""" + self._enabled = True + self._save_enabled(True) + if not self._running: + from app.services import preferences + self._interval = self._clamp_interval(preferences.get_realtime_quote_interval()) + self._running = True + self._thread = threading.Thread(target=self._poll_loop, daemon=True) + self._thread.start() + logger.info("行情服务已启用, 轮询间隔 %.1fs", self._interval) + + def disable(self) -> None: + """关闭自动行情。""" + self.stop() + logger.info("行情服务已关闭") + + def boot_check(self) -> None: + """启动时检查 preferences,若 enabled 则自动启动。""" + from app.services import preferences + if preferences.get_realtime_quotes_enabled(): + self.start() + + def set_repo(self, repo) -> None: + """注入 KlineRepository, 用于实时落盘。""" + self._repo = repo + + def set_app_state(self, app_state) -> None: + """注入 FastAPI app.state, 用于获取 strategy_monitor 等单例。""" + self._app_state = app_state + + def set_interval(self, interval: float) -> float: + """运行时更新轮询间隔(立即生效)。""" + clamped = self._clamp_interval(interval) + self._interval = clamped + from app.services import preferences + preferences.set_realtime_quote_interval(clamped) + logger.info("轮询间隔已更新为 %.1fs", clamped) + return clamped + + def get_min_interval(self) -> float: + """返回当前档位允许的最小间隔。""" + return self._tier_min_interval() + + def wait_for_update(self, timeout: float = 30.0) -> bool: + """阻塞等待下一次行情更新 (供 SSE 线程使用)。""" + self._update_event.clear() + return self._update_event.wait(timeout=timeout) + + def wait_for_alert(self, timeout: float = 30.0) -> bool: + """阻塞等待告警 (供 SSE 线程使用)。""" + self._alert_event.clear() + return self._alert_event.wait(timeout=timeout) + + def pop_alerts(self) -> list[dict]: + """取走所有待推送的告警 (线程安全)。""" + with self._lock: + alerts = self._pending_alerts + self._pending_alerts = [] + return alerts + + # ================================================================ + # 档位感知间隔限制 + # ================================================================ + + @staticmethod + def _current_tier() -> str: + """获取当前档位名(小写)。""" + from app.tickflow.policy import tier_label + return tier_label().split()[0].split("+")[0].strip().lower() + + @classmethod + def _tier_min_interval(cls) -> float: + tier = cls._current_tier() + return cls.TIER_MIN_INTERVAL.get(tier, cls.DEFAULT_INTERVAL) + + def _clamp_interval(self, interval: float) -> float: + return max(self._tier_min_interval(), min(self.MAX_INTERVAL, interval)) + + # ================================================================ + # 行情数据访问 + # ================================================================ + + def get_enriched_today(self) -> tuple[pl.DataFrame, date | None]: + """返回今天 enriched 数据 + 日期 (线程安全)。 + + 所有页面统一通过此方法获取实时行情 + 技术指标。 + """ + if not self._repo: + return pl.DataFrame(), None + return self._repo.get_enriched_latest() + + def get_quotes_compat(self) -> pl.DataFrame: + """兼容接口: 返回行情 DataFrame (用于盘中选股等需要 last_price/prev_close 的场景)。 + + 从 _enriched_cache 取 today 的数据, 只选行情基础列, 补上 last_price 别名。 + 不返回指标列, 避免 JOIN live_agg 时列名冲突。 + """ + df, _ = self.get_enriched_today() + if df.is_empty(): + return df + + # 只取盘中选股需要的行情基础列 + keep = [c for c in [ + "symbol", "close", "open", "high", "low", "volume", "amount", + "prev_close", "change_pct", "change_amount", "amplitude", "turnover_rate", + ] if c in df.columns] + df = df.select(keep) + + # enriched 的 close 等价于 last_price + if "close" in df.columns and "last_price" not in df.columns: + df = df.with_columns(pl.col("close").alias("last_price")) + return df + + def get_index_quotes(self, symbols: list[str] | None = None) -> pl.DataFrame: + """返回实时指数行情缓存。不会触发 TickFlow 请求。""" + with self._lock: + df = self._index_quotes_cache.clone() if self._index_quotes_cache is not None else pl.DataFrame() + if df.is_empty(): + return df + if symbols: + return df.filter(pl.col("symbol").is_in(symbols)) + return df + + def status(self) -> dict: + """返回行情服务状态。""" + age = (time.perf_counter() - self._fetch_time) * 1000 if self._fetch_time else -1 + return { + "enabled": self._enabled, + "running": self._running, + "interval_s": self._interval, + "symbol_count": self._symbol_count, + "index_symbol_count": self._index_symbol_count, + "quote_age_ms": round(age, 0) if age >= 0 else None, + "is_trading_hours": self._is_trading_hours(), + "last_fetch_ms": round(self._fetched_at, 0) if self._fetched_at else None, + } + + def refresh(self) -> dict: + """手动触发一次行情拉取。""" + self._fetch_quotes() + return self.status() + + # ================================================================ + # 后台轮询 + # ================================================================ + + def _poll_loop(self) -> None: + while self._running and self._enabled: + try: + if self._is_trading_hours(): + self._fetch_quotes() + else: + logger.debug("非交易时段, 跳过行情轮询") + except Exception as e: # noqa: BLE001 + logger.warning("行情轮询异常: %s", e) + + waited = 0.0 + while self._running and self._enabled and waited < self._interval: + time.sleep(0.5) + waited += 0.5 + + def _fetch_quotes(self) -> None: + """拉取全市场行情 → 写 daily + 计算 enriched + 更新缓存。""" + from app.tickflow.client import get_client + + tf = get_client() + t0 = time.perf_counter() + now_ts = time.perf_counter() + + try: + all_index_symbols = set(self._repo.get_index_symbol_set()) if self._repo else set() + all_index_symbols.update(self.CORE_INDEX_SYMBOLS) + resp = tf.quotes.get_by_universes(universes=["CN_Equity_A", "CN_Index"]) + except Exception as e: # noqa: BLE001 + logger.warning("行情拉取失败: %s", e) + return + + if not resp: + logger.warning("行情数据为空") + return + + # ---- 解析 API 响应 (临时变量, 用完丢弃) ---- + records = [] + for q in resp: + ext = q.get("ext") or {} + last_price = q.get("last_price") + prev_close = q.get("prev_close") + change_amount = ext.get("change_amount") + change_pct = ext.get("change_pct") + if change_amount is None and last_price is not None and prev_close is not None: + change_amount = float(last_price) - float(prev_close) + if change_pct is None and change_amount is not None and prev_close not in (None, 0): + change_pct = float(change_amount) / float(prev_close) * 100 + records.append({ + "symbol": q.get("symbol"), + "name": q.get("name") or ext.get("name"), + "last_price": last_price, + "prev_close": prev_close, + "open": q.get("open"), + "high": q.get("high"), + "low": q.get("low"), + "volume": q.get("volume"), + "amount": q.get("amount"), + "change_pct": change_pct, + "change_amount": change_amount, + "amplitude": ext.get("amplitude"), + "turnover_rate": ext.get("turnover_rate"), + "timestamp": q.get("timestamp"), + "session": q.get("session"), + }) + + index_records = [r for r in records if r.get("symbol") in all_index_symbols] + stock_records = [r for r in records if r.get("symbol") not in all_index_symbols] + + fetch_ms = (time.perf_counter() - t0) * 1000 + fetched_at = time.time() * 1000 + + # ---- 更新元信息 ---- + with self._lock: + self._fetch_time = now_ts + self._fetch_ms = fetch_ms + self._fetched_at = fetched_at + self._symbol_count = len(stock_records) + self._index_symbol_count = len(index_records) + self._index_quotes_cache = self._build_index_quotes(index_records) + + logger.info("行情刷新: %d 只股票, %d 只指数, 耗时 %.0fms", len(stock_records), len(index_records), fetch_ms) + + # ---- 写 kline_daily (不复权原始价格, 只有 OHLCV) ---- + daily_df = self._build_daily(stock_records) + if not daily_df.is_empty() and self._repo: + try: + self._repo.flush_live_daily(daily_df) + except Exception as e: # noqa: BLE001 + logger.warning("日K写盘失败: %s", e) + + # ---- 构建 API 直接值的补充表 (不写 daily, 只用于 enriched 计算) ---- + quote_extra = self._build_quote_extra(stock_records) + + # ---- 增量计算 enriched + 写盘 + 更新缓存 ---- + if not daily_df.is_empty() and self._repo: + self._flush_live_enriched(daily_df, quote_extra) + + # ---- 通知 SSE ---- + self._update_event.set() + + # ---- 策略监控 + 告警评估 ---- + self._evaluate_monitors(daily_df, quote_extra) + + # ================================================================ + # 工具 + # ================================================================ + + @staticmethod + def _build_daily(records: list[dict]) -> pl.DataFrame: + """将 API records 转为日K格式 DataFrame (只有 OHLCV, 写 kline_daily 用)。""" + if not records: + return pl.DataFrame() + df = pl.DataFrame(records) + cols_map = { + "symbol": "symbol", + "last_price": "close", + "open": "open", + "high": "high", + "low": "low", + "volume": "volume", + "amount": "amount", + } + select_exprs = [] + for src, dst in cols_map.items(): + if src in df.columns: + select_exprs.append(pl.col(src).alias(dst)) + if not select_exprs: + return pl.DataFrame() + result = df.select(select_exprs).with_columns( + pl.lit(date.today()).cast(pl.Date).alias("date"), + ) + # 修复: API 在非交易时段可能返回 open/high/low=0 或 null, + # 导致蜡烛从 0 开始。用 close 填充这些异常值。 + for col in ("open", "high", "low"): + if col in result.columns: + result = result.with_columns( + pl.when((pl.col(col) == 0) | pl.col(col).is_null()) + .then(pl.col("close")) + .otherwise(pl.col(col)) + .alias(col) + ) + return result + + @staticmethod + def _build_quote_extra(records: list[dict]) -> pl.DataFrame: + """构建 API 直接提供的补充字段 (不写 daily, 只传给 enriched 计算)。 + + 包含: prev_close, change_pct, change_amount, amplitude, turnover_rate。 + """ + if not records: + return pl.DataFrame() + df = pl.DataFrame(records) + keep = [c for c in [ + "symbol", "prev_close", "change_pct", "change_amount", + "amplitude", "turnover_rate", + ] if c in df.columns] + if not keep or "symbol" not in keep: + return pl.DataFrame() + return df.select(keep) + + @staticmethod + def _build_index_quotes(records: list[dict]) -> pl.DataFrame: + """构建指数实时行情缓存,不落股票 parquet。 + + 注意: API 返回的 change_pct/amplitude 是小数 (0.0366 = 3.66%), + 统一转成百分比输出, 与 _fallback_index_quotes_from_daily 口径一致 + (前端指数侧不×100, 直接 toFixed(2)% 展示)。 + """ + if not records: + return pl.DataFrame() + df = pl.DataFrame(records) + keep = [c for c in [ + "symbol", "name", "last_price", "prev_close", "open", "high", "low", + "volume", "amount", "change_pct", "change_amount", "amplitude", "timestamp", "session", + ] if c in df.columns] + if not keep or "symbol" not in keep: + return pl.DataFrame() + df = df.select(keep) + # change_pct / amplitude: 小数 → 百分比 (统一指数展示口径) + for col in ("change_pct", "amplitude"): + if col in df.columns: + df = df.with_columns((pl.col(col).cast(pl.Float64) * 100).alias(col)) + if "last_price" in df.columns and "close" not in df.columns: + df = df.with_columns(pl.col("last_price").alias("close")) + return df + + @staticmethod + def _is_trading_hours() -> bool: + now = datetime.now() + t = now.time() + morning = dt_time(9, 15) <= t <= dt_time(11, 35) + afternoon = dt_time(12, 55) <= t <= dt_time(15, 5) + return now.weekday() < 5 and (morning or afternoon) + + @staticmethod + def _save_enabled(enabled: bool) -> None: + from app.services import preferences + preferences.save({"realtime_quotes_enabled": enabled}) + + # ================================================================ + # 策略监控 + # ================================================================ + + def _evaluate_monitors(self, daily_df: pl.DataFrame, quote_extra: pl.DataFrame | None) -> None: + """行情更新后评估策略监控,并刷新策略结果缓存。""" + from app.services import preferences + + try: + # 获取 enriched 数据 (刚算好的) + enriched_today, enriched_date = self.get_enriched_today() + if enriched_today.is_empty(): + return + + all_alerts: list[dict] = [] + + # 1. 策略监控评估 + if preferences.get_strategy_monitor_enabled(): + monitor = getattr(self._app_state, "strategy_monitor", None) if self._app_state else None + if monitor and monitor.watching: + strategy_alerts = monitor.on_quote_update(enriched_today) + for a in strategy_alerts: + all_alerts.append({ + "source": "strategy", + "type": a.type, + "strategy_id": a.strategy_id, + "symbol": a.symbol, + "name": a.name, + "message": a.message, + "price": a.price, + "change_pct": a.change_pct, + "signals": a.signals, + }) + + # 2. 刷新策略结果缓存 (实时行情开启时,每轮行情更新后自动重算) + if self._enabled and self._app_state: + self._refresh_strategy_cache(enriched_today, enriched_date) + + # 推入待推送队列 + 通知 SSE + if all_alerts: + with self._lock: + self._pending_alerts.extend(all_alerts) + self._alert_event.set() + logger.info("策略监控评估完成: %d 条通知", len(all_alerts)) + + except Exception as e: # noqa: BLE001 + logger.warning("监控评估失败: %s", e) + + def _refresh_strategy_cache(self, enriched_today: pl.DataFrame, enriched_date: date | None) -> None: + """利用已计算好的 enriched 数据,运行策略池并写入缓存。""" + import math + from dataclasses import asdict + from app.services import strategy_cache + from app.services.screener import PRESET_STRATEGIES, ScreenerService + from app.strategy import config as strategy_config + + try: + if enriched_date is None: + return + as_of = enriched_date + data_dir = self._repo.store.data_dir + svc = ScreenerService(self._repo) + engine = getattr(self._app_state, "strategy_engine", None) + + # 确定要运行的策略: 策略监控池中的策略 + monitor_ids = self._get_monitor_pool_ids() + if not monitor_ids: + return + + # 一次加载所有 override + all_overrides = strategy_config.list_overrides(data_dir) + + # 历史策略: 只在需要时加载 + shared_history = None + history_strats = [] + if engine: + id_set = set(monitor_ids) + history_strats = [ + (sid, s) for sid, s in engine._strategies.items() + if s.filter_history_fn and sid in id_set + ] + if history_strats: + max_lb = max(s.lookback_days for _, s in history_strats) + shared_history = svc._load_enriched_history(as_of, max(1, max_lb)) + + results: dict[str, dict] = {} + for sid in monitor_ids: + try: + overrides = all_overrides.get(sid, {}) + bf = overrides.get("basic_filter") if overrides else None + dl = overrides.get("display_limit") if overrides else None + if dl is None and overrides and "display_limit" in overrides: + dl = 0 + + if sid in PRESET_STRATEGIES: + r = svc.run_preset(sid, as_of=as_of, precomputed=enriched_today, basic_filter=bf, display_limit=dl) + elif engine: + r = engine.run( + sid, as_of, overrides=overrides or None, + precomputed=enriched_today, precomputed_history=shared_history, + ) + if dl is not None and dl > 0: + r.rows = r.rows[:dl] + r.total = min(r.total, dl) + else: + continue + + # sanitize NaN/Inf + rows = [] + for row_dict in asdict(r).get("rows", []): + for k, v in list(row_dict.items()): + if isinstance(v, float) and not math.isfinite(v): + row_dict[k] = None + rows.append(row_dict) + results[sid] = {"total": r.total, "as_of": str(as_of), "rows": rows} + except Exception: # noqa: BLE001 + continue + + if results: + strategy_cache.write_cache(data_dir, str(as_of), results) + + except Exception as e: # noqa: BLE001 + logger.warning("策略缓存刷新失败: %s", e) + + def _get_monitor_pool_ids(self) -> list[str]: + """获取策略监控池中的策略 ID 列表。""" + from app.services import preferences + ids = preferences.get_strategy_monitor_ids() + if not ids: + return [] + return [sid for sid in ids if sid] + + @staticmethod + def _get_strategy_monitor(): + """获取 StrategyMonitorService — 不再使用, 改用 _app_state 注入。""" + return None + + # ================================================================ + # enriched 增量计算 + # ================================================================ + + def _flush_live_enriched(self, daily_df: pl.DataFrame, quote_extra: pl.DataFrame = None) -> None: + """增量计算今天的 enriched: 用昨天的递推状态 + 今天 OHLCV → 只算今天 5500 行。 + + quote_extra: API 直接提供的补充字段 (prev_close, change_pct 等), + 不写 daily, 直接传给 compute_enriched_today 避免重复计算。 + """ + try: + today = date.today() + t0 = time.perf_counter() + + # ---- 尝试增量路径 ---- + live_agg = self._repo.get_live_agg() + prev_enriched, prev_date = self._repo.get_enriched_latest() + + use_incremental = ( + not live_agg.is_empty() + and not prev_enriched.is_empty() + and prev_date is not None + ) + + if use_incremental: + from app.indicators.pipeline import compute_enriched_today + instruments = self._repo.get_instruments() + # 将 API 直接提供的补充字段 JOIN 到 daily_df + today_ohlcv = daily_df + if quote_extra is not None and not quote_extra.is_empty(): + today_ohlcv = daily_df.join(quote_extra, on="symbol", how="left") + enriched_today = compute_enriched_today( + live_agg=live_agg, + prev_enriched=prev_enriched, + today_ohlcv=today_ohlcv, + instruments=instruments, + ) + if enriched_today.is_empty(): + logger.warning("增量计算结果为空, 回退到全量计算") + use_incremental = False + + # ---- 全量回退路径 ---- + if not use_incremental: + from datetime import timedelta + from app.indicators.pipeline import compute_enriched + + logger.info("enriched 全量计算 (live_agg=%s, 上次日期=%s)", + "ok" if not live_agg.is_empty() else "空", prev_date) + + cutoff = today - timedelta(days=90) + daily_glob = str(self._repo.store.data_dir / "kline_daily" / "**" / "*.parquet") + ohlcv_cols = ["symbol", "date", "open", "high", "low", "close", "volume", "amount"] + hist_df = ( + pl.scan_parquet(daily_glob) + .filter(pl.col("date") >= cutoff) + .sort(["symbol", "date"]) + .collect() + ) + if hist_df.is_empty(): + return + + hist_cols = [c for c in ohlcv_cols if c in hist_df.columns] + hist_df = hist_df.select(hist_cols).filter(pl.col("date") != today) + daily_ohlcv = daily_df.select([c for c in ohlcv_cols if c in daily_df.columns]) + full_df = pl.concat([hist_df, daily_ohlcv], how="diagonal_relaxed") + full_df = full_df.sort(["symbol", "date"]) + + factor_path = self._repo.store.data_dir / "adj_factor" / "all.parquet" + factors = pl.DataFrame() + if factor_path.exists(): + try: + factors = pl.read_parquet(factor_path) + except Exception: + pass + instruments = self._repo.get_instruments() + + enriched_full = compute_enriched(full_df, factors=factors, instruments=instruments) + enriched_today = enriched_full.filter(pl.col("date") == today) + + if enriched_today.is_empty(): + return + + # ---- 写盘 + 更新缓存 ---- + self._repo.flush_live_enriched(enriched_today) + + elapsed = time.perf_counter() - t0 + mode_label = "增量" if use_incremental else "全量" + logger.info("enriched %s: %d 只, %s, 耗时 %.0fms", + mode_label, len(enriched_today), today, elapsed * 1000) + except Exception as e: # noqa: BLE001 + logger.warning("enriched 计算失败: %s", e) diff --git a/backend/app/services/screener.py b/backend/app/services/screener.py new file mode 100644 index 0000000..8adfa1e --- /dev/null +++ b/backend/app/services/screener.py @@ -0,0 +1,585 @@ +"""Screener 服务(§6.3)。 + +性能优化: + - enriched parquet 仅存 14 列基础数据, 指标和信号即时计算 + - preset 策略: 从内存缓存或即时计算获取完整指标, ~10-50ms + - custom SQL: DuckDB (用户传 SQL WHERE 字符串), ~10-50ms +""" +from __future__ import annotations + +import logging +import time +from dataclasses import dataclass, field +from datetime import date, timedelta + +import polars as pl + +from app.tickflow.repository import KlineRepository + +logger = logging.getLogger(__name__) + +# ── 进程级历史数据缓存 (避免 run_all 每次重新扫描 parquet + 计算指标) ── +_history_cache: dict[tuple[date, int], tuple[float, pl.DataFrame]] = {} +_HISTORY_CACHE_TTL = 120.0 # 秒 + + +# 内置预设策略 — Polars 表达式方式 +PRESET_STRATEGIES: dict[str, dict] = { + "trend_breakout": { + "name": "趋势突破", + "description": "MA60 上方 + 60 日新高 + 量能 ≥ 2 倍均量", + "filter": ( + (pl.col("close") > pl.col("ma60")) + & pl.col("signal_n_day_high").fill_null(False) + & (pl.col("vol_ratio_5d") >= 2.0) + ), + "order_by": "momentum_60d", + "descending": True, + "limit": 100, + }, + "ma_golden_cross": { + "name": "MA 金叉", + "description": "MA5 上穿 MA20 当日触发,量能配合", + "filter": ( + pl.col("signal_ma_golden_5_20").fill_null(False) + & (pl.col("vol_ratio_5d") >= 1.2) + & (pl.col("close") > pl.col("ma60")) + ), + "order_by": "momentum_20d", + "descending": True, + "limit": 100, + }, + "macd_golden": { + "name": "MACD 金叉放量", + "description": "MACD 金叉当日 + 量能放大", + "filter": ( + pl.col("signal_macd_golden").fill_null(False) + & (pl.col("vol_ratio_5d") >= 1.5) + ), + "order_by": "momentum_60d", + "descending": True, + "limit": 100, + }, + "volume_price_surge": { + "name": "量价齐升", + "description": "突破 MA20 + 放量 + 收阳", + "filter": ( + pl.col("signal_ma20_breakout").fill_null(False) + & (pl.col("vol_ratio_5d") >= 2.0) + & (pl.col("close") > pl.col("open")) + ), + "order_by": "vol_ratio_5d", + "descending": True, + "limit": 100, + }, + "low_volatility_leader": { + "name": "低波动龙头", + "description": "20 日动量为正 + 年化波动 < 30% + MA20 上方", + "filter": ( + (pl.col("momentum_20d") > 0) + & (pl.col("annual_vol_20d") < 0.30) + & (pl.col("close") > pl.col("ma20")) + ), + "order_by": "momentum_60d", + "descending": True, + "limit": 100, + }, + "broken_board_recovery": { + "name": "断板反包", + "description": "连板 ≥2 后断板 1-2 天,出现放量反包信号", + "filter": ( + pl.col("signal_limit_up").fill_null(False) + & (pl.col("vol_ratio_5d") >= 1.5) + & (pl.col("change_pct") > 0.03) + ), + "order_by": "change_pct", + "descending": True, + "limit": 100, + }, + "oversold_bounce": { + "name": "超跌反弹", + "description": "RSI14 < 30 超卖区 + 当日收阳 + 放量,抄底信号", + "filter": ( + (pl.col("rsi_14") < 30) + & (pl.col("close") > pl.col("open")) + & (pl.col("vol_ratio_5d") >= 1.2) + ), + "order_by": "rsi_14", + "descending": False, + "limit": 100, + }, + "boll_breakout": { + "name": "布林突破", + "description": "突破布林上轨 + 放量,强势加速信号", + "filter": ( + pl.col("signal_boll_breakout_upper").fill_null(False) + & (pl.col("vol_ratio_5d") >= 1.5) + ), + "order_by": "vol_ratio_5d", + "descending": True, + "limit": 100, + }, + "bullish_alignment": { + "name": "均线多头", + "description": "MA5 > MA10 > MA20 > MA60 多头排列 + 短期动量为正", + "filter": ( + (pl.col("ma5") > pl.col("ma10")) + & (pl.col("ma10") > pl.col("ma20")) + & (pl.col("ma20") > pl.col("ma60")) + & (pl.col("momentum_20d") > 0) + ), + "order_by": "momentum_60d", + "descending": True, + "limit": 100, + }, + "consecutive_limit_ups": { + "name": "连板股", + "description": "当日涨停且连续涨停 ≥ 2 天,强势追涨", + "filter": ( + pl.col("signal_limit_up").fill_null(False) + & (pl.col("consecutive_limit_ups") >= 2) + ), + "order_by": "consecutive_limit_ups", + "descending": True, + "limit": 100, + }, + "pullback_to_support": { + "name": "缩量回踩", + "description": "回踩 MA20 附近 + 缩量 + 中期趋势向上", + "filter": ( + (pl.col("close") > pl.col("ma20") * 0.98) + & (pl.col("close") < pl.col("ma20") * 1.02) + & (pl.col("vol_ratio_5d") < 0.8) + & (pl.col("close") > pl.col("ma60")) + & (pl.col("momentum_20d") > 0) + ), + "order_by": "momentum_60d", + "descending": True, + "limit": 100, + }, + "n_day_low_reversal": { + "name": "新低反转", + "description": "触及 60 日新低后当日收阳放量,反转信号", + "filter": ( + pl.col("signal_n_day_low").fill_null(False) + & (pl.col("close") > pl.col("open")) + & (pl.col("vol_ratio_5d") >= 1.5) + ), + "order_by": "change_pct", + "descending": True, + "limit": 100, + }, +} + + +@dataclass +class ScreenerResult: + as_of: date + strategy: str | None + rows: list[dict] = field(default_factory=list) + total: int = 0 + elapsed_ms: float = 0.0 + + +class ScreenerService: + def __init__(self, repo: KlineRepository) -> None: + self.repo = repo + + def _load_enriched_for_date(self, target_date: date) -> pl.DataFrame: + """从 enriched parquet 读取指定日期的基础数据并即时计算完整指标+信号。 + + enriched parquet 仅存 14 列。读取后需要即时计算 ma/ema/macd/kdj/rsi/boll/momentum/signal 等列。 + 对于最新日, 优先使用内存缓存 (已包含完整指标)。 + """ + # 优先使用 repo 最新日缓存 + cache, cache_date = self.repo.get_enriched_latest() + if cache is not None and not cache.is_empty() and cache_date == target_date: + df = cache + # JOIN instruments + df_i = self.repo.get_instruments() + if not df_i.is_empty(): + inst_cols = [c for c in ["symbol", "name", "total_shares", "float_shares"] if c in df_i.columns] + if "name" not in df.columns: + df = df.join(df_i.select(inst_cols), on="symbol", how="left") + return df + + # 尝试从 repo 级预计算历史缓存中提取目标日期 + cached_hist = self.repo.get_enriched_history(target_date, 1) + if cached_hist is not None and not cached_hist.is_empty() and "date" in cached_hist.columns: + df = cached_hist.filter(pl.col("date") == target_date) + if not df.is_empty(): + logger.debug("_load_enriched_for_date: repo history cache for %s", target_date) + # JOIN instruments + df_i = self.repo.get_instruments() + if not df_i.is_empty(): + inst_cols = [c for c in ["symbol", "name", "total_shares", "float_shares"] if c in df_i.columns] + if "name" not in df.columns: + df = df.join(df_i.select(inst_cols), on="symbol", how="left") + return df + + # 历史日期: 从 parquet 读取 14 列, 即时计算指标 (慢路径) + enriched_dir = self.repo.store.data_dir / "kline_daily_enriched" + ds = target_date.isoformat() + target_parquet = enriched_dir / f"date={ds}" / "part.parquet" + + if not target_parquet.exists(): + return pl.DataFrame() + + try: + df = pl.read_parquet(target_parquet) + except Exception as e: # noqa: BLE001 + logger.warning("load_enriched_for_date failed: %s", e) + return pl.DataFrame() + + if df.is_empty(): + return df + + # 即时计算指标: 需要加载历史窗口作 warmup + df_full = self._compute_enriched_full(df, target_date) + return df_full + + def _compute_enriched_full(self, df_target: pl.DataFrame, target_date: date) -> pl.DataFrame: + """从 14 列基础数据即时计算完整 enriched (含全部指标和信号)。 + + 读取历史数据作为指标计算的 warmup, 计算完成后只返回目标日期的行。 + """ + from app.indicators.pipeline import compute_indicators, compute_signals, compute_limit_signals + + # 加载 warmup 历史 (目标日期前 ~120 天) + enriched_dir = self.repo.store.data_dir / "kline_daily_enriched" + start = target_date - timedelta(days=150) + read_cols = ["symbol", "date", "open", "high", "low", "close", "volume", + "amount", "raw_close", "raw_high", "raw_low"] + + try: + lf = ( + pl.scan_parquet(str(enriched_dir / "**" / "*.parquet")) + .filter( + (pl.col("date") >= start) + & (pl.col("date") <= target_date) + ) + .sort(["symbol", "date"]) + ) + available = [c for c in read_cols if c in lf.schema] + df_hist = lf.select(available).collect() + except Exception as e: # noqa: BLE001 + logger.warning("warmup history load failed: %s", e) + df_hist = df_target + + if df_hist.is_empty(): + df_hist = df_target + + # 计算指标 + df_full = compute_indicators(df_hist) + df_full = compute_signals(df_full) + + # 计算涨跌停信号 (需要 instruments) + instruments = self.repo.get_instruments() + if instruments is not None and not instruments.is_empty(): + df_full = compute_limit_signals(df_full, instruments) + + # 只保留目标日期 + df_result = df_full.filter(pl.col("date") == target_date) + + # JOIN instruments (name, total_shares, float_shares) + if not instruments.is_empty(): + inst_cols = [c for c in ["symbol", "name", "total_shares", "float_shares"] if c in instruments.columns] + if "name" not in df_result.columns: + df_result = df_result.join(instruments.select(inst_cols), on="symbol", how="left") + + return df_result + + def _load_enriched_history(self, target_date: date, lookback_days: int) -> pl.DataFrame: + """读取目标日期之前的基础行情数据, 供历史窗口策略使用。 + + 优先从 repo 内存缓存获取 (启动时已预计算), 命中时 0ms。 + 缓存 miss 时走 scan_parquet + compute_indicators 慢路径。 + """ + # 优先级 1: repo 级预计算缓存 (启动时 _refresh_enriched 已计算完整历史) + t0 = time.perf_counter() + cached = self.repo.get_enriched_history(target_date, lookback_days) + if cached is not None and not cached.is_empty(): + # JOIN instruments (repo 缓存不含 name 等列) + instruments = self.repo.get_instruments() + if instruments is not None and not instruments.is_empty() and "name" not in cached.columns: + inst_cols = [c for c in ["symbol", "name", "total_shares", "float_shares"] + if c in instruments.columns] + cached = cached.join(instruments.select(inst_cols), on="symbol", how="left") + elapsed = (time.perf_counter() - t0) * 1000 + logger.info("_load_enriched_history(%s, %d): repo cache hit, %.1fms, %d rows", + target_date, lookback_days, elapsed, len(cached)) + return cached + + # 优先级 2: 进程级 history_cache (之前的 TTL 缓存) + cache_key = (target_date, lookback_days) + now = time.monotonic() + ttl_cached = _history_cache.get(cache_key) + if ttl_cached is not None: + ts, cached_df = ttl_cached + if now - ts < _HISTORY_CACHE_TTL: + logger.debug("history TTL cache hit: %s lookback=%d", target_date, lookback_days) + return cached_df + del _history_cache[cache_key] + + # 优先级 3: scan_parquet + compute_indicators (慢路径, ~5s) + logger.warning("_load_enriched_history cache miss, computing indicators (%s, %d)...", + target_date, lookback_days) + from app.indicators.pipeline import compute_indicators, compute_signals, compute_limit_signals + + warmup = 60 + start = target_date - timedelta(days=min((lookback_days + warmup) * 2, 180)) + + enriched_dir = self.repo.store.data_dir / "kline_daily_enriched" + read_cols = ["symbol", "date", "open", "high", "low", "close", "volume", + "amount", "raw_close", "raw_high", "raw_low"] + + try: + lf = ( + pl.scan_parquet(str(enriched_dir / "**" / "*.parquet")) + .filter((pl.col("date") >= start) & (pl.col("date") <= target_date)) + .sort(["symbol", "date"]) + ) + available = [c for c in read_cols if c in lf.collect_schema().names()] + df_hist = lf.select(available).collect() + except Exception as e: # noqa: BLE001 + logger.warning("load_enriched_history failed: %s", e) + return pl.DataFrame() + + if df_hist.is_empty(): + return pl.DataFrame() + + df_full = compute_indicators(df_hist) + df_full = compute_signals(df_full) + + instruments = self.repo.get_instruments() + if instruments is not None and not instruments.is_empty(): + df_full = compute_limit_signals(df_full, instruments) + + if instruments is not None and not instruments.is_empty(): + inst_cols = [c for c in ["symbol", "name", "total_shares", "float_shares"] if c in instruments.columns] + if "name" not in df_full.columns: + df_full = df_full.join(instruments.select(inst_cols), on="symbol", how="left") + + # 裁剪掉 warmup 部分, 只保留 lookback 范围 (减少 group_by 开销) + lookback_start = target_date - timedelta(days=lookback_days) + if "date" in df_full.columns: + df_full = df_full.filter(pl.col("date") >= lookback_start) + + df_full = df_full.sort(["symbol", "date"]) + + elapsed = (time.perf_counter() - t0) * 1000 + logger.info("_load_enriched_history(%s, %d): computed in %.1fms, %d rows", + target_date, lookback_days, elapsed, len(df_full)) + + _history_cache[cache_key] = (now, df_full) + if len(_history_cache) > 10: + expired = [k for k, (ts, _) in _history_cache.items() if now - ts > _HISTORY_CACHE_TTL] + for k in expired: + del _history_cache[k] + + return df_full + + def run( + self, + as_of: date, + conditions: list[str], + order_by: str | None = None, + limit: int = 30, + pool: list[str] | None = None, + ) -> ScreenerResult: + """自定义 SQL 条件选股。 + + 先通过 Polars 即时计算完整指标, 再用 DuckDB 做 SQL WHERE 过滤。 + kline_enriched DuckDB 视图只有 14 列, 不能直接用于指标过滤。 + """ + t0 = time.perf_counter() + + if not conditions: + return ScreenerResult(as_of=as_of, strategy=None) + + # 从即时计算获取完整 enriched 数据 + df = self._load_enriched_for_date(as_of) + if df.is_empty(): + return ScreenerResult(as_of=as_of, strategy=None) + + # Pool 过滤 + if pool: + df = df.filter(pl.col("symbol").is_in(pool)) + + # 用 DuckDB 做 SQL 过滤 (注册临时视图) + try: + import duckdb + con = duckdb.connect(database=":memory:") + con.register("enriched", df.to_arrow()) + where = " AND ".join(f"({c})" for c in conditions) + sql = f"SELECT * FROM enriched WHERE {where}" + if order_by: + sql += f" ORDER BY {order_by}" + if limit: + sql += f" LIMIT {limit}" + df_result = con.execute(sql).pl() + con.close() + except Exception as e: # noqa: BLE001 + logger.warning("screener SQL query failed: %s", e) + df_result = pl.DataFrame() + + rows = df_result.to_dicts() if not df_result.is_empty() else [] + elapsed = (time.perf_counter() - t0) * 1000 + + return ScreenerResult( + as_of=as_of, + strategy=None, + rows=rows, + total=len(rows), + elapsed_ms=elapsed, + ) + + def run_preset( + self, + strategy_id: str, + as_of: date, + pool: list[str] | None = None, + precomputed: pl.DataFrame | None = None, + basic_filter: dict | None = None, + display_limit: int | None = None, + ) -> ScreenerResult: + """预设策略选股 — 从 enriched 读取预计算好的指标列后过滤。 + + - precomputed 不为空: 直接复用(run_all 场景) + - precomputed 为空: 从 enriched 读目标日期 + - basic_filter: 用户保存的基础参数过滤(boards、价格等) + """ + t0 = time.perf_counter() + + strat = PRESET_STRATEGIES.get(strategy_id) + if not strat: + raise ValueError(f"unknown strategy: {strategy_id}") + + if precomputed is not None and not precomputed.is_empty(): + df = precomputed + else: + df = self._load_enriched_for_date(as_of) + if df.is_empty(): + return ScreenerResult(as_of=as_of, strategy=strategy_id) + + # 应用用户基础参数过滤(boards、价格区间等) + if basic_filter and basic_filter.get("enabled", True): + df = self._apply_basic_filter(df, basic_filter) + + # 应用策略过滤 + df = df.filter(strat["filter"]) + + # 应用 pool + if pool: + df = df.filter(pl.col("symbol").is_in(pool)) + + # 排序 + 限制 + order_col = strat["order_by"] + if order_col in df.columns: + df = df.sort(order_col, descending=strat.get("descending", True)) + + # display_limit: None=不限制, 0=全部, N=前N个 + if display_limit == 0: + limit = None # 不限制 + elif display_limit is not None: + limit = display_limit + else: + limit = None # 未配置时默认不限制 + if limit is not None and limit > 0: + df = df.head(limit) + + # 基于排序列生成 0-100 评分 (与 StrategyEngine 统一) + if order_col in df.columns and not df.is_empty(): + col_vals = df[order_col].cast(pl.Float64) + col_min = col_vals.min() + col_max = col_vals.max() + col_range = col_max - col_min + if col_range and col_range > 0: + normalized = (col_vals - col_min) / col_range + else: + normalized = pl.Series("norm", [0.5] * len(df)) + if not strat.get("descending", True): + normalized = 1.0 - normalized + df = df.with_columns((normalized * 100).alias("score")) + + rows = df.to_dicts() + elapsed = (time.perf_counter() - t0) * 1000 + + # sanitize + for r in rows: + for k, v in list(r.items()): + if isinstance(v, float) and (v != v or abs(v) == float("inf")): + r[k] = None + + return ScreenerResult( + as_of=as_of, + strategy=strategy_id, + rows=rows, + total=len(rows), + elapsed_ms=elapsed, + ) + + @staticmethod + def _apply_basic_filter(df: pl.DataFrame, bf: dict) -> pl.DataFrame: + """应用用户基础参数过滤(boards、价格区间、市值等)""" + exprs: list[pl.Expr] = [] + if bf.get("price_min") is not None: + exprs.append(pl.col("close") >= bf["price_min"]) + if bf.get("price_max") is not None: + exprs.append(pl.col("close") <= bf["price_max"]) + if bf.get("float_cap_min") is not None and "float_shares" in df.columns: + exprs.append(pl.col("close") * pl.col("float_shares") >= bf["float_cap_min"]) + if bf.get("float_cap_max") is not None and "float_shares" in df.columns: + exprs.append(pl.col("close") * pl.col("float_shares") <= bf["float_cap_max"]) + if bf.get("amount_min") is not None: + exprs.append(pl.col("amount") >= bf["amount_min"]) + if bf.get("amount_max") is not None: + exprs.append(pl.col("amount") <= bf["amount_max"]) + if bf.get("turnover_min") is not None and "turnover_rate" in df.columns: + exprs.append(pl.col("turnover_rate") >= bf["turnover_min"]) + if bf.get("turnover_max") is not None and "turnover_rate" in df.columns: + exprs.append(pl.col("turnover_rate") <= bf["turnover_max"]) + if bf.get("exclude_st") and "name" in df.columns: + exprs.append(~pl.col("name").str.contains("(?i)ST|\\*ST|退")) + # 板块过滤 + boards = bf.get("boards") + if boards and isinstance(boards, list) and len(boards) > 0: + board_exprs: list[pl.Expr] = [] + for b in boards: + if b == "沪主板": + board_exprs.append(pl.col("symbol").str.starts_with("60")) + elif b == "深主板": + board_exprs.append( + pl.col("symbol").str.starts_with("00") + | pl.col("symbol").str.starts_with("001") + ) + elif b == "创业板": + board_exprs.append( + pl.col("symbol").str.starts_with("300") + | pl.col("symbol").str.starts_with("301") + ) + elif b == "科创板": + board_exprs.append(pl.col("symbol").str.starts_with("688")) + elif b == "北交所": + board_exprs.append(pl.col("symbol").str.contains(r"\.BJ$")) + if board_exprs: + exprs.append(pl.any_horizontal(board_exprs)) + if exprs: + return df.filter(pl.all_horizontal(exprs)) + return df + + def latest_date(self) -> date | None: + d = self.repo.enriched_latest_date() + if d: + return d + # 回退 DuckDB + try: + res = self.repo.execute_one( + "SELECT max(date) FROM kline_enriched", + ) + if res and res[0]: + d = res[0] + return d if isinstance(d, date) else date.fromisoformat(str(d)) + except Exception: # noqa: BLE001 + return None + return None diff --git a/backend/app/services/strategy_cache.py b/backend/app/services/strategy_cache.py new file mode 100644 index 0000000..7dc700f --- /dev/null +++ b/backend/app/services/strategy_cache.py @@ -0,0 +1,150 @@ +"""策略结果缓存 — 写入本地文件,供策略页面秒加载。 + +缓存结构: + { + "as_of": "2024-01-15", + "results": { strategy_id: { total, as_of, rows } }, + "today_ever_matched": { strategy_id: [symbol, ...] }, // 今日曾命中 symbol 并集 + "today_ever_rows": { strategy_id: { symbol: row_data } },// 今日曾命中的完整行数据 + "updated_at": 1705324800000 # Unix ms + } + +文件路径: data/user_data/strategy_cache.json +""" +from __future__ import annotations + +import json +import logging +import time +from datetime import date, datetime +from pathlib import Path +from typing import Any + + +def _json_default(obj: Any) -> Any: + """处理 date/datetime 等 JSON 不认识的类型。""" + if isinstance(obj, date): + return obj.isoformat() + if isinstance(obj, datetime): + return obj.isoformat() + raise TypeError(f"Object of type {type(obj).__name__} is not JSON serializable") + + +logger = logging.getLogger(__name__) + +_CACHE_FILENAME = "strategy_cache.json" + + +def _cache_path(data_dir: Path) -> Path: + return data_dir / "user_data" / _CACHE_FILENAME + + +def _enriched_parquet_path(data_dir: Path, as_of: str) -> Path: + """返回 enriched parquet 文件路径。""" + return data_dir / "kline_daily_enriched" / f"date={as_of}" / "part.parquet" + + +def _get_enriched_mtime(data_dir: Path, as_of: str) -> float | None: + """返回 enriched parquet 文件的 mtime (秒)。文件不存在返回 None。""" + p = _enriched_parquet_path(data_dir, as_of) + try: + return p.stat().st_mtime + except FileNotFoundError: + return None + + +def read_cache(data_dir: Path) -> dict | None: + """读取策略缓存文件。返回 None 表示无缓存、读取失败或 enriched 数据已更新导致缓存过期。""" + path = _cache_path(data_dir) + if not path.exists(): + return None + try: + text = path.read_text(encoding="utf-8") + if not text.strip(): + return None + cached = json.loads(text) + except Exception as e: # noqa: BLE001 + logger.warning("读取策略缓存失败: %s", e) + return None + + # 校验 enriched mtime: 数据文件变化 → 缓存过期 + as_of = cached.get("as_of") + stored_mtime = cached.get("enriched_mtime") + if as_of and stored_mtime: + current_mtime = _get_enriched_mtime(data_dir, as_of) + if current_mtime is not None and current_mtime != stored_mtime: + logger.info("策略缓存过期: enriched 数据已更新 (as_of=%s)", as_of) + return None + + return cached + + +def _rows_to_symbol_map(rows: list[dict]) -> dict[str, dict]: + """将 rows 列表转为 {symbol: row_data} 映射。""" + result: dict[str, dict] = {} + for row in rows: + sym = row.get("symbol") + if sym: + result[sym] = row + return result + + +def write_cache( + data_dir: Path, + as_of: str, + results: dict[str, Any], +) -> None: + """将策略结果写入缓存文件,同时更新今日曾命中集合。 + + - 日期变更时重置 today_ever_matched 和 today_ever_rows + - 同一天内合并 (并集) 之前曾命中的 symbol,并用最新行数据更新 + """ + path = _cache_path(data_dir) + path.parent.mkdir(parents=True, exist_ok=True) + + # 读取旧缓存 + old = read_cache(data_dir) + old_as_of = old.get("as_of") if old else None + old_ever_rows: dict[str, dict[str, dict]] = old.get("today_ever_rows", {}) if old else {} + + # 当前命中的行数据 → symbol 映射 + current_row_maps: dict[str, dict[str, dict]] = {} + for sid, r in results.items(): + current_row_maps[sid] = _rows_to_symbol_map(r.get("rows", [])) + + if old_as_of and old_as_of == as_of and old_ever_rows: + # 同一天: 合并 — 用当前行数据更新旧数据 (保持最新价格等) + merged_rows: dict[str, dict[str, dict]] = {} + all_keys = set(old_ever_rows.keys()) | set(current_row_maps.keys()) + for sid in all_keys: + old_map = old_ever_rows.get(sid, {}) + cur_map = current_row_maps.get(sid, {}) + # 以旧数据为基础,用当前数据覆盖 (当前数据更新鲜) + combined = {**old_map, **cur_map} + merged_rows[sid] = combined + today_ever_rows = merged_rows + else: + # 新的一天或首次写入 + today_ever_rows = current_row_maps + + # 从 ever_rows 提取 symbol 列表 (用于快速计数) + today_ever_matched = {sid: sorted(maps.keys()) for sid, maps in today_ever_rows.items()} + + # 记录 enriched parquet 文件的 mtime,用于后续校验缓存是否过期 + enriched_mtime = _get_enriched_mtime(data_dir, as_of) + + payload = { + "as_of": as_of, + "results": results, + "today_ever_matched": today_ever_matched, + "today_ever_rows": today_ever_rows, + "enriched_mtime": enriched_mtime, + "updated_at": int(time.time() * 1000), + } + try: + path.write_text(json.dumps(payload, ensure_ascii=False, default=_json_default), encoding="utf-8") + total_rows = sum(len(r.get("rows", [])) for r in results.values()) + total_ever = sum(len(v) for v in today_ever_matched.values()) + logger.info("策略缓存已写入: %s, %d 策略, %d 命中, %d 曾命中", as_of, len(results), total_rows, total_ever) + except Exception as e: # noqa: BLE001 + logger.warning("写入策略缓存失败: %s", e) diff --git a/backend/app/services/watchlist.py b/backend/app/services/watchlist.py new file mode 100644 index 0000000..6b7a30e --- /dev/null +++ b/backend/app/services/watchlist.py @@ -0,0 +1,126 @@ +"""自选股服务(§6.1)。 + +存储:`data/user_data/watchlist.parquet`,字段 symbol + added_at + note。 +""" +from __future__ import annotations + +import logging +from datetime import datetime +from pathlib import Path + +import polars as pl + +from app.config import settings +from app.tickflow.capabilities import Cap, CapabilitySet +from app.tickflow.client import get_client + +logger = logging.getLogger(__name__) + + +def _path() -> Path: + p = settings.data_dir / "user_data" / "watchlist.parquet" + p.parent.mkdir(parents=True, exist_ok=True) + return p + + +def list_symbols() -> list[dict]: + p = _path() + if not p.exists(): + return [] + df = pl.read_parquet(p) + if df.is_empty(): + return [] + return df.to_dicts() + + +def add(symbol: str, note: str = "") -> list[dict]: + p = _path() + if p.exists(): + df = pl.read_parquet(p) + # 已存在则先移除,后面重新插入到最前面 + if symbol in df["symbol"].to_list(): + df = df.filter(pl.col("symbol") != symbol) + else: + df = pl.DataFrame(schema={"symbol": pl.Utf8, "added_at": pl.Utf8, "note": pl.Utf8}) + + new_row = pl.DataFrame({ + "symbol": [symbol], + "added_at": [datetime.utcnow().isoformat(timespec="seconds")], + "note": [note], + }) + out = pl.concat([new_row, df], how="diagonal_relaxed") + out.write_parquet(p) + return out.to_dicts() + + +def remove(symbol: str) -> list[dict]: + p = _path() + if not p.exists(): + return [] + df = pl.read_parquet(p) + df = df.filter(pl.col("symbol") != symbol) + df.write_parquet(p) + return df.to_dicts() + + +def clear() -> int: + """清空自选列表。返回移除的数量。""" + p = _path() + if not p.exists(): + return 0 + df = pl.read_parquet(p) + count = df.height + if count > 0: + pl.DataFrame(schema={"symbol": pl.Utf8, "added_at": pl.Utf8, "note": pl.Utf8}).write_parquet(p) + return count + + +def fetch_quotes(symbols: list[str], capset: CapabilitySet, timeout_s: float = 8.0) -> list[dict]: + """拉取实时行情。 + + 优先用 quote.batch;否则降级为 quote.by_symbol 单股请求。 + timeout_s: 单批次请求超时(秒),防止 API 卡死阻塞整个请求。 + """ + from concurrent.futures import ThreadPoolExecutor, TimeoutError as FuturesTimeout + + if not symbols: + return [] + + tf = get_client() + quotes: list[dict] = [] + + # 走 batch + batch_size = 5 + if capset.has(Cap.QUOTE_BATCH): + lim = capset.limits(Cap.QUOTE_BATCH) + batch_size = lim.batch if lim and lim.batch else 50 + elif capset.has(Cap.QUOTE_BY_SYMBOL): + lim = capset.limits(Cap.QUOTE_BY_SYMBOL) + batch_size = lim.batch if lim and lim.batch else 5 + + chunks = [symbols[i:i + batch_size] for i in range(0, len(symbols), batch_size)] + + # 用线程池为每个批次加超时保护 + pool = ThreadPoolExecutor(max_workers=1) + for chunk in chunks: + try: + future = pool.submit(tf.quotes.get, symbols=chunk, as_dataframe=True) + raw = future.result(timeout=timeout_s) + if raw is None or len(raw) == 0: + continue + df = pl.from_pandas(raw) + rename_map = { + "last_price": "price", + "ext.change_pct": "pct", + "ext.name": "name", + } + df = df.rename({k: v for k, v in rename_map.items() if k in df.columns}) + quotes.extend(df.to_dicts()) + except FuturesTimeout: + logger.warning("quote fetch timeout (%.1fs) for %d symbols", timeout_s, len(chunk)) + break # 超时后不再尝试后续批次 + except Exception as e: # noqa: BLE001 + logger.warning("quote fetch failed for %d symbols: %s", len(chunk), e) + pool.shutdown(wait=False) + + return quotes diff --git a/backend/app/strategy/__init__.py b/backend/app/strategy/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/app/strategy/ai_generator.py b/backend/app/strategy/ai_generator.py new file mode 100644 index 0000000..0346a9f --- /dev/null +++ b/backend/app/strategy/ai_generator.py @@ -0,0 +1,149 @@ +"""AI 策略生成器 — 读取策略开发文档 + 调用 LLM 生成策略代码。 + +职责: 接收用户自然语言描述 → 读取 docs/strategy-guide.md → 调用 LLM → 返回策略代码。 +不知道: 引擎内部、API、前端、配置持久化、回测。 +""" +from __future__ import annotations + +import ast +import logging +import re +import tempfile +from pathlib import Path + +logger = logging.getLogger(__name__) + +# 策略开发文档路径 +GUIDE_PATH = Path(__file__).resolve().parent.parent.parent.parent / "docs" / "strategy-guide.md" + +_SYSTEM_PREFIX = """你是A股量化策略设计专家。根据用户描述的需求,参考下方的《策略开发指南》生成一个完整的策略Python文件。 + +要求: +1. 用户可能调整的策略阈值通过 META["params"] 暴露;公式常数、固定窗口边界、布尔开关不必强行参数化 +2. 遵循指南中的文件结构模板,但优先贴合用户规则,不要为了套模板歪曲策略含义 +3. 优先使用 Polars 表达式、窗口函数、聚合和 with_columns/filter 实现,避免逐行/逐股 Python 循环;只有表达式难以描述的复杂状态机才使用 partition_by/to_dicts +4. 只 import polars as pl,不 import 其他模块 +5. 直接输出Python代码,不要输出其他内容 + +--- 策略开发指南 --- + +""" + + +class AIStrategyGenerator: + """AI 策略生成器""" + + def __init__(self) -> None: + self._guide_cache: str | None = None + + def _get_guide(self) -> str: + if self._guide_cache is None: + if GUIDE_PATH.exists(): + self._guide_cache = GUIDE_PATH.read_text(encoding="utf-8") + else: + logger.warning("strategy-guide.md not found at %s", GUIDE_PATH) + self._guide_cache = "" + return self._guide_cache + + async def generate(self, user_prompt: str) -> dict: + """根据用户描述生成策略代码 + + Returns: {"code": str, "meta": dict, "valid": bool, "error": str | None} + """ + guide = self._get_guide() + + # 调用 LLM + code = await self._call_llm(user_prompt, guide) + + # 验证 + try: + self._validate_safety(code) + except ValueError as e: + return {"code": code, "meta": {}, "valid": False, "error": str(e)} + + # 试加载获取 META + try: + meta = self._extract_meta(code) + except Exception as e: + return {"code": code, "meta": {}, "valid": False, "error": f"解析META失败: {e}"} + + return {"code": code, "meta": meta, "valid": True, "error": None} + + async def _call_llm(self, user_prompt: str, guide: str) -> str: + """调用 OpenAI 兼容 API(流式,避免 CDN 长连接超时)""" + from openai import AsyncOpenAI + from app import secrets_store + + ai_key = secrets_store.get_ai_key() + if not ai_key: + raise RuntimeError("AI API Key 未配置,请在设置页面配置") + + client = AsyncOpenAI( + api_key=ai_key, + base_url=secrets_store.get_ai_config("ai_base_url", "https://api.alysc.top"), + timeout=180.0, + max_retries=2, + ) + # 使用流式请求:CDN 收到首个 token 后会持续转发,不会因等待超时 + stream = await client.chat.completions.create( + model=secrets_store.get_ai_config("ai_model", "gpt-5.5"), + messages=[ + {"role": "system", "content": _SYSTEM_PREFIX + guide}, + {"role": "user", "content": user_prompt}, + ], + temperature=0.3, + max_tokens=3000, + stream=True, + ) + chunks: list[str] = [] + async for chunk in stream: + delta = chunk.choices[0].delta if chunk.choices else None + if delta and delta.content: + chunks.append(delta.content) + content = "".join(chunks).strip() + # 提取代码块 + if "```python" in content: + content = content.split("```python", 1)[1].split("```", 1)[0].strip() + elif "```" in content: + content = content.split("```", 1)[1].split("```", 1)[0].strip() + return content + + @staticmethod + def _validate_safety(code: str) -> None: + """AST 级安全检查""" + tree = ast.parse(code) + + forbidden_modules = {"os", "sys", "subprocess", "socket", "shutil", + "pathlib", "http", "urllib", "requests", "httpx"} + forbidden_calls = {"open", "exec", "eval", "compile", "__import__", + "globals", "locals", "vars", "dir", "getattr", + "setattr", "delattr", "type", "input"} + + for node in ast.walk(tree): + if isinstance(node, ast.Import): + for alias in node.names: + if alias.name.split(".")[0] not in ("polars",): + if alias.name.split(".")[0] in forbidden_modules: + raise ValueError(f"禁止 import {alias.name}") + if isinstance(node, ast.ImportFrom): + if node.module and node.module.split(".")[0] not in ("polars",): + if node.module.split(".")[0] in forbidden_modules: + raise ValueError(f"禁止 from {node.module} import") + if isinstance(node, ast.Call): + if isinstance(node.func, ast.Name) and node.func.id in forbidden_calls: + raise ValueError(f"禁止调用 {node.func.id}()") + + @staticmethod + def _extract_meta(code: str) -> dict: + """从代码字符串中提取 META 字典(不执行代码)""" + tree = ast.parse(code) + for node in ast.walk(tree): + if isinstance(node, ast.Assign): + for target in node.targets: + if isinstance(target, ast.Name) and target.id == "META": + # 找到 META 赋值,用 compile+eval 安全提取 + # 只允许字面量 + meta_node = node.value + code_obj = compile(ast.Expression(meta_node), "", "eval") + return eval(code_obj, {"__builtins__": {}}) # noqa: S307 + return {} diff --git a/backend/app/strategy/builtin/__init__.py b/backend/app/strategy/builtin/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/app/strategy/builtin/boll_breakout.py b/backend/app/strategy/builtin/boll_breakout.py new file mode 100644 index 0000000..cb86588 --- /dev/null +++ b/backend/app/strategy/builtin/boll_breakout.py @@ -0,0 +1,31 @@ +"""布林突破 — 突破布林上轨 + 放量""" +import polars as pl + +META = { + "id": "boll_breakout", + "name": "布林突破", + "description": "突破布林上轨 + 放量, 强势加速信号", + "tags": ["布林", "突破"], + "params": [ + {"id": "vol_ratio_min", "label": "最低量比", "type": "float", + "default": 1.5, "min": 0.5, "max": 5.0, "step": 0.1}, + ], + "scoring": {"vol_ratio_5d": 0.4, "change_pct": 0.3, "momentum_20d": 0.3}, + "order_by": "score", + "descending": True, + "limit": 100, +} + +ENTRY_SIGNALS = ["signal_boll_breakout_upper"] +EXIT_SIGNALS = ["signal_boll_breakdown_lower"] +STOP_LOSS = -0.06 +MAX_HOLD_DAYS = 15 +ALERTS = [] + + +def filter(df: pl.DataFrame, params: dict) -> pl.Expr: + vol_min = params.get("vol_ratio_min", 1.5) + return ( + pl.col("signal_boll_breakout_upper").fill_null(False) + & (pl.col("vol_ratio_5d") >= vol_min) + ) diff --git a/backend/app/strategy/builtin/broken_board_recovery.py b/backend/app/strategy/builtin/broken_board_recovery.py new file mode 100644 index 0000000..4fd9b5e --- /dev/null +++ b/backend/app/strategy/builtin/broken_board_recovery.py @@ -0,0 +1,35 @@ +"""断板反包 — 涨停 + 放量 + 涨幅 >3%""" +import polars as pl + +META = { + "id": "broken_board_recovery", + "name": "断板反包", + "description": "连板≥2后断板1-2天, 出现放量反包信号", + "tags": ["涨停", "反包"], + "params": [ + {"id": "vol_ratio_min", "label": "最低量比", "type": "float", + "default": 1.5, "min": 0.5, "max": 5.0, "step": 0.1}, + {"id": "change_pct_min", "label": "最低涨幅", "type": "float", + "default": 0.03, "min": 0.01, "max": 0.10, "step": 0.01}, + ], + "scoring": {"change_pct": 0.4, "vol_ratio_5d": 0.3, "momentum_5d": 0.3}, + "order_by": "score", + "descending": True, + "limit": 100, +} + +ENTRY_SIGNALS = ["signal_limit_up"] +EXIT_SIGNALS = ["signal_ma20_breakdown"] +STOP_LOSS = -0.06 +MAX_HOLD_DAYS = 10 +ALERTS = [] + + +def filter(df: pl.DataFrame, params: dict) -> pl.Expr: + vol_min = params.get("vol_ratio_min", 1.5) + chg_min = params.get("change_pct_min", 0.03) + return ( + pl.col("signal_limit_up").fill_null(False) + & (pl.col("vol_ratio_5d") >= vol_min) + & (pl.col("change_pct") > chg_min) + ) diff --git a/backend/app/strategy/builtin/bullish_alignment.py b/backend/app/strategy/builtin/bullish_alignment.py new file mode 100644 index 0000000..8dc3fc1 --- /dev/null +++ b/backend/app/strategy/builtin/bullish_alignment.py @@ -0,0 +1,29 @@ +"""均线多头 — MA5>MA10>MA20>MA60 + 短期动量为正""" +import polars as pl + +META = { + "id": "bullish_alignment", + "name": "均线多头", + "description": "MA5>MA10>MA20>MA60多头排列 + 短期动量为正", + "tags": ["均线", "多头"], + "params": [], + "scoring": {"momentum_60d": 0.4, "momentum_20d": 0.3, "turnover_rate": 0.3}, + "order_by": "score", + "descending": True, + "limit": 100, +} + +ENTRY_SIGNALS = ["signal_ma_golden_5_20", "signal_ma_golden_20_60"] +EXIT_SIGNALS = ["signal_ma_dead_5_20", "signal_ma20_breakdown"] +STOP_LOSS = -0.06 +MAX_HOLD_DAYS = 20 +ALERTS = [] + + +def filter(df: pl.DataFrame, params: dict) -> pl.Expr: + return ( + (pl.col("ma5") > pl.col("ma10")) + & (pl.col("ma10") > pl.col("ma20")) + & (pl.col("ma20") > pl.col("ma60")) + & (pl.col("momentum_20d") > 0) + ) diff --git a/backend/app/strategy/builtin/consecutive_limit_ups.py b/backend/app/strategy/builtin/consecutive_limit_ups.py new file mode 100644 index 0000000..4e864ac --- /dev/null +++ b/backend/app/strategy/builtin/consecutive_limit_ups.py @@ -0,0 +1,31 @@ +"""连板股 — 涨停且连续涨停≥2天""" +import polars as pl + +META = { + "id": "consecutive_limit_ups", + "name": "连板股", + "description": "当日涨停且连续涨停≥2天, 强势追涨", + "tags": ["涨停", "连板"], + "params": [ + {"id": "min_boards", "label": "最少连板数", "type": "int", + "default": 2, "min": 1, "max": 20, "step": 1}, + ], + "scoring": {"consecutive_limit_ups": 0.5, "change_pct": 0.3, "amount": 0.2}, + "order_by": "score", + "descending": True, + "limit": 100, +} + +ENTRY_SIGNALS = ["signal_limit_up"] +EXIT_SIGNALS = [] +STOP_LOSS = -0.05 +MAX_HOLD_DAYS = 5 +ALERTS = [] + + +def filter(df: pl.DataFrame, params: dict) -> pl.Expr: + min_boards = params.get("min_boards", 2) + return ( + pl.col("signal_limit_up").fill_null(False) + & (pl.col("consecutive_limit_ups") >= min_boards) + ) diff --git a/backend/app/strategy/builtin/high_turnover_surge.py b/backend/app/strategy/builtin/high_turnover_surge.py new file mode 100644 index 0000000..53b8276 --- /dev/null +++ b/backend/app/strategy/builtin/high_turnover_surge.py @@ -0,0 +1,34 @@ +"""高换手拉升 — 换手率 > 5% 且涨幅 > 3%, 资金活跃""" +import polars as pl + +META = { + "id": "high_turnover_surge", + "name": "高换手拉升", + "description": "换手率 > 5% 且涨幅 > 3%, 资金活跃", + "tags": ["换手率", "放量", "资金"], + "params": [ + {"id": "min_turnover", "label": "最低换手率%", "type": "float", + "default": 5.0, "min": 1.0, "max": 20.0, "step": 0.5}, + {"id": "min_change", "label": "最低涨幅%", "type": "float", + "default": 3.0, "min": 1.0, "max": 10.0, "step": 0.5}, + ], + "scoring": {"turnover_rate": 0.4, "change_pct": 0.3, "momentum_5d": 0.3}, + "order_by": "score", + "descending": True, + "limit": 50, +} + +ENTRY_SIGNALS = ["signal_volume_surge"] +EXIT_SIGNALS = ["signal_ma20_breakdown"] +STOP_LOSS = -0.05 +MAX_HOLD_DAYS = 10 +ALERTS = [] + + +def filter(df: pl.DataFrame, params: dict) -> pl.Expr: + min_to = params.get("min_turnover", 5.0) / 100.0 + min_chg = params.get("min_change", 3.0) / 100.0 + return ( + (pl.col("turnover_rate") > min_to) + & (pl.col("change_pct") > min_chg) + ) diff --git a/backend/app/strategy/builtin/limit_up_momentum.py b/backend/app/strategy/builtin/limit_up_momentum.py new file mode 100644 index 0000000..65afe29 --- /dev/null +++ b/backend/app/strategy/builtin/limit_up_momentum.py @@ -0,0 +1,34 @@ +"""连板接力 — 近2日涨停且今日涨幅 > 5%, 连板股追踪""" +import polars as pl + +META = { + "id": "limit_up_momentum", + "name": "连板接力", + "description": "连板股 + 今日涨幅 > 5%, 连板接力追踪", + "tags": ["涨停", "连板", "接力"], + "params": [ + {"id": "min_change", "label": "最低涨幅%", "type": "float", + "default": 5.0, "min": 2.0, "max": 15.0, "step": 0.5}, + {"id": "min_boards", "label": "最少连板", "type": "int", + "default": 1, "min": 1, "max": 10, "step": 1}, + ], + "scoring": {"consecutive_limit_ups": 0.4, "change_pct": 0.3, "amount": 0.3}, + "order_by": "score", + "descending": True, + "limit": 50, +} + +ENTRY_SIGNALS = ["signal_limit_up"] +EXIT_SIGNALS = [] +STOP_LOSS = -0.05 +MAX_HOLD_DAYS = 5 +ALERTS = [] + + +def filter(df: pl.DataFrame, params: dict) -> pl.Expr: + min_chg = params.get("min_change", 5.0) / 100.0 + min_boards = params.get("min_boards", 1) + return ( + (pl.col("change_pct") > min_chg) + & (pl.col("consecutive_limit_ups") >= min_boards) + ) diff --git a/backend/app/strategy/builtin/low_volatility_leader.py b/backend/app/strategy/builtin/low_volatility_leader.py new file mode 100644 index 0000000..f32a3a8 --- /dev/null +++ b/backend/app/strategy/builtin/low_volatility_leader.py @@ -0,0 +1,32 @@ +"""低波动龙头 — 正动量 + 低波动 + MA20上方""" +import polars as pl + +META = { + "id": "low_volatility_leader", + "name": "低波动龙头", + "description": "20日动量为正 + 年化波动 < 30% + MA20上方", + "tags": ["低波动", "龙头"], + "params": [ + {"id": "vol_max", "label": "最大年化波动", "type": "float", + "default": 0.30, "min": 0.05, "max": 1.0, "step": 0.01}, + ], + "scoring": {"momentum_60d": 0.4, "momentum_20d": 0.3, "turnover_rate": 0.3}, + "order_by": "score", + "descending": True, + "limit": 100, +} + +ENTRY_SIGNALS = ["signal_ma20_breakout"] +EXIT_SIGNALS = ["signal_ma20_breakdown"] +STOP_LOSS = -0.05 +MAX_HOLD_DAYS = 30 +ALERTS = [] + + +def filter(df: pl.DataFrame, params: dict) -> pl.Expr: + vol_max = params.get("vol_max", 0.30) + return ( + (pl.col("momentum_20d") > 0) + & (pl.col("annual_vol_20d") < vol_max) + & (pl.col("close") > pl.col("ma20")) + ) diff --git a/backend/app/strategy/builtin/ma_golden_cross.py b/backend/app/strategy/builtin/ma_golden_cross.py new file mode 100644 index 0000000..81b81fb --- /dev/null +++ b/backend/app/strategy/builtin/ma_golden_cross.py @@ -0,0 +1,32 @@ +"""MA金叉 — MA5上穿MA20 + 量能配合 + MA60上方""" +import polars as pl + +META = { + "id": "ma_golden_cross", + "name": "MA 金叉", + "description": "MA5上穿MA20当日触发, 量能配合", + "tags": ["均线", "金叉"], + "params": [ + {"id": "vol_ratio_min", "label": "最低量比", "type": "float", + "default": 1.2, "min": 0.5, "max": 5.0, "step": 0.1}, + ], + "scoring": {"momentum_20d": 0.5, "vol_ratio_5d": 0.3, "change_pct": 0.2}, + "order_by": "score", + "descending": True, + "limit": 100, +} + +ENTRY_SIGNALS = ["signal_ma_golden_5_20"] +EXIT_SIGNALS = ["signal_ma_dead_5_20"] +STOP_LOSS = -0.06 +MAX_HOLD_DAYS = 15 +ALERTS = [] + + +def filter(df: pl.DataFrame, params: dict) -> pl.Expr: + vol_min = params.get("vol_ratio_min", 1.2) + return ( + pl.col("signal_ma_golden_5_20").fill_null(False) + & (pl.col("vol_ratio_5d") >= vol_min) + & (pl.col("close") > pl.col("ma60")) + ) diff --git a/backend/app/strategy/builtin/macd_golden.py b/backend/app/strategy/builtin/macd_golden.py new file mode 100644 index 0000000..2ea8006 --- /dev/null +++ b/backend/app/strategy/builtin/macd_golden.py @@ -0,0 +1,31 @@ +"""MACD金叉放量 — MACD金叉当日 + 量能放大""" +import polars as pl + +META = { + "id": "macd_golden", + "name": "MACD 金叉放量", + "description": "MACD金叉当日 + 量能放大", + "tags": ["MACD", "金叉", "放量"], + "params": [ + {"id": "vol_ratio_min", "label": "最低量比", "type": "float", + "default": 1.5, "min": 0.5, "max": 5.0, "step": 0.1}, + ], + "scoring": {"momentum_60d": 0.4, "vol_ratio_5d": 0.3, "change_pct": 0.3}, + "order_by": "score", + "descending": True, + "limit": 100, +} + +ENTRY_SIGNALS = ["signal_macd_golden"] +EXIT_SIGNALS = ["signal_macd_dead"] +STOP_LOSS = -0.07 +MAX_HOLD_DAYS = 20 +ALERTS = [] + + +def filter(df: pl.DataFrame, params: dict) -> pl.Expr: + vol_min = params.get("vol_ratio_min", 1.5) + return ( + pl.col("signal_macd_golden").fill_null(False) + & (pl.col("vol_ratio_5d") >= vol_min) + ) diff --git a/backend/app/strategy/builtin/n_day_low_reversal.py b/backend/app/strategy/builtin/n_day_low_reversal.py new file mode 100644 index 0000000..11219c2 --- /dev/null +++ b/backend/app/strategy/builtin/n_day_low_reversal.py @@ -0,0 +1,32 @@ +"""新低反转 — 60日新低后收阳放量""" +import polars as pl + +META = { + "id": "n_day_low_reversal", + "name": "新低反转", + "description": "触及60日新低后当日收阳放量, 反转信号", + "tags": ["反转", "新低"], + "params": [ + {"id": "vol_ratio_min", "label": "最低量比", "type": "float", + "default": 1.5, "min": 0.5, "max": 5.0, "step": 0.1}, + ], + "scoring": {"change_pct": 0.4, "vol_ratio_5d": 0.3, "momentum_5d": 0.3}, + "order_by": "score", + "descending": True, + "limit": 100, +} + +ENTRY_SIGNALS = ["signal_n_day_low"] +EXIT_SIGNALS = ["signal_ma20_breakdown"] +STOP_LOSS = -0.06 +MAX_HOLD_DAYS = 15 +ALERTS = [] + + +def filter(df: pl.DataFrame, params: dict) -> pl.Expr: + vol_min = params.get("vol_ratio_min", 1.5) + return ( + pl.col("signal_n_day_low").fill_null(False) + & (pl.col("close") > pl.col("open")) + & (pl.col("vol_ratio_5d") >= vol_min) + ) diff --git a/backend/app/strategy/builtin/near_limit_up.py b/backend/app/strategy/builtin/near_limit_up.py new file mode 100644 index 0000000..4442e06 --- /dev/null +++ b/backend/app/strategy/builtin/near_limit_up.py @@ -0,0 +1,55 @@ +"""逼近涨停 — 涨幅 > 7% 且距涨停 < 3%, 盘后选股""" +import polars as pl + + +def _limit_pct() -> pl.Expr: + """根据板块和 ST 动态计算涨跌幅限制 (小数)。 + 创业板(300/301)/科创板(688): 20% + 北交所(.BJ): 30% + ST: 5% + 主板: 10% + """ + is_st = pl.col("name").str.contains("(?i)ST").fill_null(False) + is_cyb = pl.col("symbol").str.starts_with("300") | pl.col("symbol").str.starts_with("301") + is_kcb = pl.col("symbol").str.starts_with("688") + is_bj = pl.col("symbol").str.contains(r"\.BJ$") + return ( + pl.when(is_st).then(0.05) + .when(is_cyb | is_kcb).then(0.20) + .when(is_bj).then(0.30) + .otherwise(0.10) + ) + + +META = { + "id": "near_limit_up", + "name": "逼近涨停", + "description": "涨幅 > 7% 且距涨停 < 3%, 追涨信号", + "tags": ["涨停", "追涨"], + "params": [ + {"id": "min_change", "label": "最低涨幅%", "type": "float", + "default": 7.0, "min": 3.0, "max": 15.0, "step": 1.0}, + {"id": "limit_gap", "label": "距涨停空间%", "type": "float", + "default": 3.0, "min": 1.0, "max": 10.0, "step": 0.5}, + ], + "scoring": {"change_pct": 0.5, "amount": 0.3, "momentum_5d": 0.2}, + "order_by": "score", + "descending": True, + "limit": 50, +} + +ENTRY_SIGNALS = [] +EXIT_SIGNALS = ["signal_ma20_breakdown"] +STOP_LOSS = -0.05 +MAX_HOLD_DAYS = 5 +ALERTS = [] + + +def filter(df: pl.DataFrame, params: dict) -> pl.Expr: + min_chg = params.get("min_change", 7.0) / 100.0 + gap = params.get("limit_gap", 3.0) / 100.0 + lp = _limit_pct() + return ( + (pl.col("change_pct") > min_chg) + & (pl.col("change_pct") < lp - gap) + ) diff --git a/backend/app/strategy/builtin/oversold_bounce.py b/backend/app/strategy/builtin/oversold_bounce.py new file mode 100644 index 0000000..8adc124 --- /dev/null +++ b/backend/app/strategy/builtin/oversold_bounce.py @@ -0,0 +1,37 @@ +"""超跌反弹 — RSI14 < 30 + 收阳 + 放量""" +import polars as pl + +META = { + "id": "oversold_bounce", + "name": "超跌反弹", + "description": "RSI14 < 30超卖区 + 当日收阳 + 放量, 抄底信号", + "tags": ["超跌", "反弹", "RSI"], + "params": [ + {"id": "rsi_max", "label": "RSI上限", "type": "float", + "default": 30.0, "min": 10.0, "max": 50.0, "step": 1.0}, + {"id": "vol_ratio_min", "label": "最低量比", "type": "float", + "default": 1.2, "min": 0.5, "max": 5.0, "step": 0.1}, + ], + "scoring": {"change_pct": 0.3, "vol_ratio_5d": 0.3, "momentum_5d": 0.2, "rsi_14": 0.2}, + "order_by": "score", + "descending": True, + "limit": 100, +} + +ENTRY_SIGNALS = [] +EXIT_SIGNALS = ["signal_ma20_breakdown"] +STOP_LOSS = -0.05 +MAX_HOLD_DAYS = 15 +ALERTS = [ + {"field": "rsi_14", "op": "<", "value": 25, "message": "RSI极度超卖"}, +] + + +def filter(df: pl.DataFrame, params: dict) -> pl.Expr: + rsi_max = params.get("rsi_max", 30.0) + vol_min = params.get("vol_ratio_min", 1.2) + return ( + (pl.col("rsi_14") < rsi_max) + & (pl.col("close") > pl.col("open")) + & (pl.col("vol_ratio_5d") >= vol_min) + ) diff --git a/backend/app/strategy/builtin/oversold_reversal.py b/backend/app/strategy/builtin/oversold_reversal.py new file mode 100644 index 0000000..ba31a6b --- /dev/null +++ b/backend/app/strategy/builtin/oversold_reversal.py @@ -0,0 +1,37 @@ +"""超跌反弹 — RSI14 < 30 + 涨幅 > 1% + 站上 MA5, 超卖反弹信号""" +import polars as pl + +META = { + "id": "oversold_reversal", + "name": "超跌反转", + "description": "RSI14 < 30超卖 + 涨幅 > 1% + 站上MA5, 超卖反转信号", + "tags": ["超跌", "反弹", "RSI"], + "params": [ + {"id": "rsi_max", "label": "RSI上限", "type": "float", + "default": 30.0, "min": 10.0, "max": 50.0, "step": 1.0}, + {"id": "min_change", "label": "最低涨幅%", "type": "float", + "default": 1.0, "min": 0.5, "max": 5.0, "step": 0.5}, + ], + "scoring": {"change_pct": 0.4, "rsi_14": 0.3, "vol_ratio_5d": 0.3}, + "order_by": "score", + "descending": True, + "limit": 50, +} + +ENTRY_SIGNALS = [] +EXIT_SIGNALS = ["signal_ma20_breakdown"] +STOP_LOSS = -0.05 +MAX_HOLD_DAYS = 15 +ALERTS = [ + {"field": "rsi_14", "op": "<", "value": 25, "message": "RSI极度超卖"}, +] + + +def filter(df: pl.DataFrame, params: dict) -> pl.Expr: + rsi_max = params.get("rsi_max", 30.0) + min_chg = params.get("min_change", 1.0) / 100.0 + return ( + (pl.col("rsi_14") < rsi_max) + & (pl.col("change_pct") > min_chg) + & (pl.col("close") > pl.col("ma5")) + ) diff --git a/backend/app/strategy/builtin/pullback_ma20_bounce.py b/backend/app/strategy/builtin/pullback_ma20_bounce.py new file mode 100644 index 0000000..9c56adb --- /dev/null +++ b/backend/app/strategy/builtin/pullback_ma20_bounce.py @@ -0,0 +1,34 @@ +"""均线回踩反弹 — 价格在 MA20 附近(±2%)且 MA 多头排列, 回踩买入""" +import polars as pl + +META = { + "id": "pullback_ma20_bounce", + "name": "均线回踩反弹", + "description": "价格在MA20附近(±2%)且MA5>MA20>MA60多头排列, 回踩买入", + "tags": ["回踩", "均线", "反弹"], + "params": [ + {"id": "ma_proximity", "label": "MA偏离度%", "type": "float", + "default": 2.0, "min": 0.5, "max": 5.0, "step": 0.5}, + ], + "scoring": {"momentum_60d": 0.4, "change_pct": 0.3, "momentum_20d": 0.3}, + "order_by": "score", + "descending": True, + "limit": 50, +} + +ENTRY_SIGNALS = ["signal_ma_golden_5_20"] +EXIT_SIGNALS = ["signal_ma20_breakdown", "signal_ma_dead_5_20"] +STOP_LOSS = -0.05 +MAX_HOLD_DAYS = 15 +ALERTS = [] + + +def filter(df: pl.DataFrame, params: dict) -> pl.Expr: + proximity = params.get("ma_proximity", 2.0) / 100.0 + return ( + (pl.col("close") > pl.col("ma20") * (1 - proximity)) + & (pl.col("close") < pl.col("ma20") * (1 + proximity)) + & (pl.col("ma5") > pl.col("ma20")) + & (pl.col("ma20") > pl.col("ma60")) + & (pl.col("change_pct") > 0) + ) diff --git a/backend/app/strategy/builtin/pullback_to_support.py b/backend/app/strategy/builtin/pullback_to_support.py new file mode 100644 index 0000000..36fc51a --- /dev/null +++ b/backend/app/strategy/builtin/pullback_to_support.py @@ -0,0 +1,37 @@ +"""缩量回踩 — 回踩MA20附近 + 缩量 + 中期趋势向上""" +import polars as pl + +META = { + "id": "pullback_to_support", + "name": "缩量回踩", + "description": "回踩MA20附近 + 缩量 + 中期趋势向上", + "tags": ["回踩", "支撑"], + "params": [ + {"id": "ma_proximity", "label": "均线偏离度", "type": "float", + "default": 0.02, "min": 0.01, "max": 0.05, "step": 0.005}, + {"id": "vol_ratio_max", "label": "最大量比", "type": "float", + "default": 0.8, "min": 0.2, "max": 1.5, "step": 0.1}, + ], + "scoring": {"momentum_60d": 0.4, "momentum_20d": 0.3, "turnover_rate": 0.3}, + "order_by": "score", + "descending": True, + "limit": 100, +} + +ENTRY_SIGNALS = ["signal_ma_golden_5_20"] +EXIT_SIGNALS = ["signal_ma20_breakdown"] +STOP_LOSS = -0.05 +MAX_HOLD_DAYS = 20 +ALERTS = [] + + +def filter(df: pl.DataFrame, params: dict) -> pl.Expr: + proximity = params.get("ma_proximity", 0.02) + vol_max = params.get("vol_ratio_max", 0.8) + return ( + (pl.col("close") > pl.col("ma20") * (1 - proximity)) + & (pl.col("close") < pl.col("ma20") * (1 + proximity)) + & (pl.col("vol_ratio_5d") < vol_max) + & (pl.col("close") > pl.col("ma60")) + & (pl.col("momentum_20d") > 0) + ) diff --git a/backend/app/strategy/builtin/strong_open.py b/backend/app/strategy/builtin/strong_open.py new file mode 100644 index 0000000..918842b --- /dev/null +++ b/backend/app/strategy/builtin/strong_open.py @@ -0,0 +1,35 @@ +"""强势高开 — 高开 > 3% 且保持上涨, 集合竞价强势""" +import polars as pl + +META = { + "id": "strong_open", + "name": "强势高开", + "description": "高开 > 3% 且收盘高于开盘价, 集合竞价强势", + "tags": ["高开", "强势"], + "params": [ + {"id": "min_open_gap", "label": "最低高开%", "type": "float", + "default": 3.0, "min": 1.0, "max": 10.0, "step": 0.5}, + {"id": "min_change", "label": "最低涨幅%", "type": "float", + "default": 3.0, "min": 1.0, "max": 10.0, "step": 0.5}, + ], + "scoring": {"change_pct": 0.4, "amplitude": 0.2, "amount": 0.4}, + "order_by": "score", + "descending": True, + "limit": 50, +} + +ENTRY_SIGNALS = [] +EXIT_SIGNALS = ["signal_ma20_breakdown"] +STOP_LOSS = -0.05 +MAX_HOLD_DAYS = 10 +ALERTS = [] + + +def filter(df: pl.DataFrame, params: dict) -> pl.Expr: + min_gap = params.get("min_open_gap", 3.0) / 100.0 + min_chg = params.get("min_change", 3.0) / 100.0 + return ( + (pl.col("open") > pl.col("prev_close") * (1 + min_gap)) + & (pl.col("close") > pl.col("open")) + & (pl.col("change_pct") > min_chg) + ) diff --git a/backend/app/strategy/builtin/trend_breakout.py b/backend/app/strategy/builtin/trend_breakout.py new file mode 100644 index 0000000..eb95cca --- /dev/null +++ b/backend/app/strategy/builtin/trend_breakout.py @@ -0,0 +1,42 @@ +"""趋势突破 — MA60上方 + 60日新高 + 放量""" +import polars as pl + +META = { + "id": "trend_breakout", + "name": "趋势突破", + "description": "MA60上方 + 60日新高 + 量能 ≥ 2倍均量", + "tags": ["趋势", "突破", "放量"], + "basic_filter": { + "price_min": 5, + "price_max": 200, + "market_cap_min": 20e8, + "amount_min": 1e8, + "exclude_st": True, + "exclude_new_days": 60, + }, + "params": [ + {"id": "vol_ratio_min", "label": "最低量比", "type": "float", + "default": 2.0, "min": 0.5, "max": 10.0, "step": 0.1}, + ], + "scoring": {"momentum_60d": 0.4, "vol_ratio_5d": 0.3, "change_pct": 0.3}, + "order_by": "score", + "descending": True, + "limit": 100, +} + +ENTRY_SIGNALS = ["signal_n_day_high"] +EXIT_SIGNALS = ["signal_ma20_breakdown"] +STOP_LOSS = -0.08 +MAX_HOLD_DAYS = 20 +ALERTS = [ + {"field": "signal_volume_surge", "message": "放量异动"}, +] + + +def filter(df: pl.DataFrame, params: dict) -> pl.Expr: + vol_min = params.get("vol_ratio_min", 2.0) + return ( + (pl.col("close") > pl.col("ma60")) + & pl.col("signal_n_day_high").fill_null(False) + & (pl.col("vol_ratio_5d") >= vol_min) + ) diff --git a/backend/app/strategy/builtin/volume_price_surge.py b/backend/app/strategy/builtin/volume_price_surge.py new file mode 100644 index 0000000..c3573e4 --- /dev/null +++ b/backend/app/strategy/builtin/volume_price_surge.py @@ -0,0 +1,32 @@ +"""量价齐升 — 突破MA20 + 放量 + 收阳""" +import polars as pl + +META = { + "id": "volume_price_surge", + "name": "量价齐升", + "description": "突破MA20 + 放量 + 收阳", + "tags": ["量价", "突破"], + "params": [ + {"id": "vol_ratio_min", "label": "最低量比", "type": "float", + "default": 2.0, "min": 0.5, "max": 10.0, "step": 0.1}, + ], + "scoring": {"vol_ratio_5d": 0.4, "change_pct": 0.3, "momentum_20d": 0.3}, + "order_by": "score", + "descending": True, + "limit": 100, +} + +ENTRY_SIGNALS = ["signal_ma20_breakout"] +EXIT_SIGNALS = ["signal_ma20_breakdown"] +STOP_LOSS = -0.06 +MAX_HOLD_DAYS = 15 +ALERTS = [] + + +def filter(df: pl.DataFrame, params: dict) -> pl.Expr: + vol_min = params.get("vol_ratio_min", 2.0) + return ( + pl.col("signal_ma20_breakout").fill_null(False) + & (pl.col("vol_ratio_5d") >= vol_min) + & (pl.col("close") > pl.col("open")) + ) diff --git a/backend/app/strategy/config.py b/backend/app/strategy/config.py new file mode 100644 index 0000000..3c594f7 --- /dev/null +++ b/backend/app/strategy/config.py @@ -0,0 +1,71 @@ +"""策略配置持久化 — 读写用户覆盖值。 + +职责: 将每个策略的用户定制设置(基础参数、策略参数、评分、买卖信号)持久化到 JSON。 +不知道: 引擎、AI、前端、回测。 +存储: data/user_data/strategy_overrides/{strategy_id}.json +""" +from __future__ import annotations + +import json +import logging +from pathlib import Path + +logger = logging.getLogger(__name__) + + +def _overrides_dir(data_dir: Path) -> Path: + d = data_dir / "user_data" / "strategy_overrides" + d.mkdir(parents=True, exist_ok=True) + return d + + +def _path(data_dir: Path, strategy_id: str) -> Path: + return _overrides_dir(data_dir) / f"{strategy_id}.json" + + +def load_override(data_dir: Path, strategy_id: str) -> dict: + """读取策略的用户覆盖配置,不存在返回空 dict""" + p = _path(data_dir, strategy_id) + if not p.exists(): + return {} + try: + data = json.loads(p.read_text(encoding="utf-8")) + # 清理 basic_filter 中值为 None/空的键(避免固化无意义的空值) + bf = data.get("basic_filter") + if isinstance(bf, dict): + cleaned = {k: v for k, v in bf.items() if v is not None} + if cleaned: + data["basic_filter"] = cleaned + else: + del data["basic_filter"] + return data + except Exception as e: + logger.warning("load override %s failed: %s", strategy_id, e) + return {} + + +def save_override(data_dir: Path, strategy_id: str, overrides: dict) -> None: + """保存策略的用户覆盖配置(全量覆盖写)""" + p = _path(data_dir, strategy_id) + p.parent.mkdir(parents=True, exist_ok=True) + p.write_text(json.dumps(overrides, ensure_ascii=False, indent=2), encoding="utf-8") + + +def delete_override(data_dir: Path, strategy_id: str) -> None: + """删除策略的用户覆盖配置(重置为默认值)""" + p = _path(data_dir, strategy_id) + if p.exists(): + p.unlink() + + +def list_overrides(data_dir: Path) -> dict[str, dict]: + """返回所有策略的覆盖配置 {strategy_id: overrides}""" + d = _overrides_dir(data_dir) + result: dict[str, dict] = {} + for f in d.glob("*.json"): + try: + sid = f.stem + result[sid] = json.loads(f.read_text(encoding="utf-8")) + except Exception: + continue + return result diff --git a/backend/app/strategy/custom_signals.py b/backend/app/strategy/custom_signals.py new file mode 100644 index 0000000..cc05a83 --- /dev/null +++ b/backend/app/strategy/custom_signals.py @@ -0,0 +1,207 @@ +"""自定义信号 — 用户用「字段 + 运算符 + 值」组合出的布尔信号。 + +职责: + - 从 data/user_data/custom_signals/*.json 加载信号定义 + - 把每个信号的 conditions 编译成一条 Polars 布尔表达式(AND 组合) + - 供 pipeline 在 compute_signals / compute_enriched_today 末尾注入为列 + +不知道: 引擎、AI、API、回测、监控。纯函数 + 模块级缓存。 + +设计: + - 信号列名加前缀 ``csg_`` 避免与内置 ``signal_`` 列冲突。 + - 回测/选股/监控都按列名找信号,因此注入列后零特殊处理即可三处生效。 + - 字段白名单 + 固定运算符集,杜绝任意表达式注入。 + - 第一版只支持 AND(多条件同时满足)。 +""" +from __future__ import annotations + +import json +import logging +import re +from pathlib import Path + +import polars as pl + +logger = logging.getLogger(__name__) + +# ── 常量 ──────────────────────────────────────────────── +PREFIX = "csg_" # 自定义信号列名前缀 +ID_RE = re.compile(r"^[a-z0-9_]{1,40}$") +OPS = {">", ">=", "<", "<=", "==", "!="} + +# 字段白名单:只允许这些列出现在条件里(防注入)。均为数值型。 +# 与 ENRICHED_COLUMNS 的数值列保持一致,排除 symbol/date/name 等非数值列。 +ALLOWED_FIELDS: frozenset[str] = frozenset({ + # 行情 + "open", "high", "low", "close", "volume", "amount", "turnover_rate", + "consecutive_limit_ups", "consecutive_limit_downs", + # 基础 + "prev_close", "change_pct", "change_amount", "amplitude", + # 均线 / 指数均线 + "ma5", "ma10", "ma20", "ma30", "ma60", + "ema5", "ema10", "ema20", "ema30", "ema60", + # MACD / BOLL / KDJ / ATR + "macd_dif", "macd_dea", "macd_hist", + "boll_upper", "boll_lower", + "kdj_k", "kdj_d", "kdj_j", + "atr_14", + # 量价 / 极值 / 动量 / 波动率 / RSI + "vol_ma5", "vol_ma10", "vol_ratio_5d", + "high_60d", "low_60d", + "momentum_5d", "momentum_10d", "momentum_20d", "momentum_30d", "momentum_60d", + "annual_vol_20d", + "rsi_6", "rsi_14", "rsi_24", +}) + +# 运算符 → Polars 表达式构造器(输入 col_expr, value) +_OP_BUILDERS = { + ">": lambda c, v: c > v, + ">=": lambda c, v: c >= v, + "<": lambda c, v: c < v, + "<=": lambda c, v: c <= v, + "==": lambda c, v: c == v, + "!=": lambda c, v: c != v, +} + + +# ── 持久化(镜像 strategy/config.py 的写法)────────────── +def _dir(data_dir: Path) -> Path: + d = data_dir / "user_data" / "custom_signals" + d.mkdir(parents=True, exist_ok=True) + return d + + +def _path(data_dir: Path, signal_id: str) -> Path: + return _dir(data_dir) / f"{signal_id}.json" + + +def load_all(data_dir: Path) -> list[dict]: + """读取全部自定义信号定义。损坏的文件被跳过。""" + d = _dir(data_dir) + out: list[dict] = [] + for f in sorted(d.glob("*.json")): + try: + out.append(json.loads(f.read_text(encoding="utf-8"))) + except Exception as e: + logger.warning("custom signal load failed %s: %s", f.name, e) + return out + + +def save_one(data_dir: Path, sig: dict) -> None: + p = _path(data_dir, sig["id"]) + p.parent.mkdir(parents=True, exist_ok=True) + p.write_text(json.dumps(sig, ensure_ascii=False, indent=2), encoding="utf-8") + + +def delete_one(data_dir: Path, signal_id: str) -> bool: + p = _path(data_dir, signal_id) + if p.exists(): + p.unlink() + return True + return False + + +# ── 校验 ──────────────────────────────────────────────── +def _parse_right(right: str) -> tuple[str, object]: + """解析右值。返回 ('field', colname) 或 ('const', float)。""" + if isinstance(right, (int, float)): + return ("const", float(right)) + if not isinstance(right, str): + raise ValueError(f"非法右值: {right!r}") + if right.startswith("field:"): + col = right[len("field:"):] + if col not in ALLOWED_FIELDS: + raise ValueError(f"右值字段不在白名单: {col}") + return ("field", col) + # 纯数字 + try: + return ("const", float(right)) + except ValueError: + raise ValueError(f"非法右值(应为 field:xxx 或数字): {right!r}") + + +def validate(sig: dict) -> None: + """校验一个信号定义,非法则抛 ValueError(含中文信息)。""" + sid = sig.get("id", "") + if not isinstance(sid, str) or not ID_RE.match(sid): + raise ValueError(f"信号 id 非法(仅小写字母数字下划线,1-40字符): {sid!r}") + if not isinstance(sig.get("name"), str) or not sig["name"].strip(): + raise ValueError("信号 name 不能为空") + if sig.get("kind") not in ("entry", "exit", "both"): + raise ValueError("kind 必须是 entry / exit / both") + conds = sig.get("conditions") + if not isinstance(conds, list) or len(conds) == 0: + raise ValueError("conditions 不能为空") + if len(conds) > 8: + raise ValueError("conditions 最多 8 条") + for i, c in enumerate(conds): + if not isinstance(c, dict): + raise ValueError(f"第 {i+1} 个条件格式错误") + left = c.get("left", "") + if left not in ALLOWED_FIELDS: + raise ValueError(f"第 {i+1} 个条件: 字段 {left!r} 不在白名单") + if c.get("op") not in OPS: + raise ValueError(f"第 {i+1} 个条件: 运算符 {c.get('op')!r} 非法") + _parse_right(c.get("right")) # 会校验右值字段/数字 + + +# ── 编译为 Polars 表达式 ───────────────────────────────── +def column_name(signal_id: str) -> str: + """信号 id → DataFrame 列名(加前缀)。""" + return f"{PREFIX}{signal_id}" + + +def build_expressions(signals: list[dict]) -> dict[str, pl.Expr]: + """把多个自定义信号编译成 {column_name: pl.Expr}。 + + - 只处理 enabled != False 的信号。 + - 单个信号内多条件用 ``&`` 串联(AND)。 + - 编译失败的信号被跳过并告警(不影响其它信号)。 + """ + out: dict[str, pl.Expr] = {} + for sig in signals: + if sig.get("enabled") is False: + continue + try: + conds = sig["conditions"] + col_name = column_name(sig["id"]) + parts: list[pl.Expr] = [] + for c in conds: + left = c["left"] + op = c["op"] + kind, val = _parse_right(c["right"]) + right_expr = pl.col(val) if kind == "field" else val + parts.append(_OP_BUILDERS[op](pl.col(left), right_expr)) + combined = parts[0] + for p in parts[1:]: + combined = combined & p + out[col_name] = combined + except Exception as e: + logger.warning("custom signal compile failed %s: %s", sig.get("id"), e) + return out + + +def inject(df: pl.DataFrame, exprs: dict[str, pl.Expr]) -> pl.DataFrame: + """把编译好的信号表达式作为列加入 df。仅添加 df 已含其依赖列的信号。""" + if df.is_empty() or not exprs: + return df + cols = set(df.columns) + add: dict[str, pl.Expr] = {} + for name, expr in exprs.items(): + # 提取该表达式引用的所有字段列,缺失则跳过(避免运行时报错) + needed = _expr_root_columns(expr) + if needed.issubset(cols): + add[name] = expr + if add: + df = df.with_columns([e.alias(n) for n, e in add.items()]) + return df + + +def _expr_root_columns(expr: pl.Expr) -> set[str]: + """尽力提取表达式里出现的列名。失败则返回空集(保守跳过)。""" + try: + # Polars 的 meta.root_names() 返回表达式引用的根列名 + names = expr.meta.root_names() + return set(names) + except Exception: + return set() diff --git a/backend/app/strategy/engine.py b/backend/app/strategy/engine.py new file mode 100644 index 0000000..67ef2ad --- /dev/null +++ b/backend/app/strategy/engine.py @@ -0,0 +1,453 @@ +"""策略引擎 — 加载、执行、评分。 + +职责: 从文件系统加载策略 Python 模块,执行两阶段过滤(基础+策略), + 通用评分排序。 +不知道: AI、API、前端、配置持久化、回测。 +""" +from __future__ import annotations + +import importlib.util +import logging +import time +from dataclasses import dataclass, field +from datetime import date +from pathlib import Path +from typing import Any, Callable + +import polars as pl + +logger = logging.getLogger(__name__) + +# 引擎级默认基础过滤 — 策略未定义 BASIC_FILTER 时兜底 +DEFAULT_BASIC_FILTER: dict = { + "price_min": 3, + "price_max": 300, + "market_cap_min": 10e8, + "float_cap_min": None, + "float_cap_max": None, + "amount_min": 0.2e8, + "amount_max": None, + "turnover_min": None, + "turnover_max": None, + "exclude_st": True, + "exclude_new_days": 30, + "boards": ["沪主板", "深主板", "创业板", "科创板", "北交所"], +} + + +@dataclass +class StrategyDef: + """加载后的策略定义(只读数据 + filter 函数引用)""" + meta: dict + basic_filter: dict + entry_signals: list[str] + exit_signals: list[str] + stop_loss: float | None + trailing_stop: float | None + trailing_take_profit_activate: float | None + trailing_take_profit_drawdown: float | None + max_hold_days: int | None + alerts: list[dict] + filter_fn: Callable[[pl.DataFrame, dict], pl.Expr] | None + filter_history_fn: Callable[[pl.DataFrame, dict], pl.DataFrame] | None + lookback_days: int + source: str # "builtin" | "custom" | "ai" + file_path: Path | None = None + + +@dataclass +class StrategyResult: + """策略执行结果""" + as_of: date + strategy_id: str + rows: list[dict] = field(default_factory=list) + total: int = 0 + elapsed_ms: float = 0.0 + scores: dict[str, float] = field(default_factory=dict) + + +class StrategyEngine: + """策略引擎 — 策略加载 + 执行 + 评分""" + + def __init__(self, enriched_loader: Callable[[date], pl.DataFrame], + enriched_history_loader: Callable[[date, int], pl.DataFrame] | None = None, + strategy_dirs: list[Path] | None = None): + """ + Args: + enriched_loader: (date) -> pl.DataFrame, 加载指定日期的 enriched 数据 + strategy_dirs: 策略文件搜索目录列表 + """ + self._loader = enriched_loader + self._history_loader = enriched_history_loader + self._strategies: dict[str, StrategyDef] = {} + self._strategy_dirs = strategy_dirs or [] + self._load_all() + + # ================================================================ + # 加载 + # ================================================================ + + def _load_all(self) -> None: + self._strategies.clear() + for d in self._strategy_dirs: + if not d.exists(): + continue + for f in sorted(d.glob("*.py")): + if f.name.startswith("_"): + continue + try: + s = self._load_file(f) + self._strategies[s.meta["id"]] = s + logger.debug("loaded strategy: %s (%s)", s.meta["id"], s.source) + except Exception as e: + logger.warning("load strategy %s failed: %s", f.name, e) + + @staticmethod + def _load_file(path: Path) -> StrategyDef: + """从 Python 文件加载策略定义""" + spec = importlib.util.spec_from_file_location(path.stem, path) + if spec is None or spec.loader is None: + raise ValueError(f"cannot load module from {path}") + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + + meta = getattr(mod, "META", {}) + meta.setdefault("id", path.stem) + meta.setdefault("name", path.stem) + meta.setdefault("description", "") + meta.setdefault("tags", []) + meta.setdefault("params", []) + meta.setdefault("scoring", {}) + meta.setdefault("order_by", "score") + meta.setdefault("descending", True) + meta.setdefault("limit", 100) + + # 合并默认基础过滤 + bf = {**DEFAULT_BASIC_FILTER} + strat_bf = getattr(mod, "BASIC_FILTER", None) + if strat_bf: + bf.update(strat_bf) + # meta 里的 basic_filter 也合并(优先级最高) + meta_bf = meta.get("basic_filter") + if meta_bf: + bf.update(meta_bf) + + source = "custom" + if "builtin" in str(path).replace("\\", "/"): + source = "builtin" + elif "/ai/" in str(path).replace("\\", "/") or "\\ai\\" in str(path): + source = "ai" + + return StrategyDef( + meta=meta, + basic_filter=bf, + entry_signals=getattr(mod, "ENTRY_SIGNALS", []), + exit_signals=getattr(mod, "EXIT_SIGNALS", []), + stop_loss=getattr(mod, "STOP_LOSS", None), + trailing_stop=getattr(mod, "TRAILING_STOP", None), + trailing_take_profit_activate=getattr(mod, "TRAILING_TAKE_PROFIT_ACTIVATE", None), + trailing_take_profit_drawdown=getattr(mod, "TRAILING_TAKE_PROFIT_DRAWDOWN", None), + max_hold_days=getattr(mod, "MAX_HOLD_DAYS", None), + alerts=getattr(mod, "ALERTS", []), + filter_fn=getattr(mod, "filter", None), + filter_history_fn=getattr(mod, "filter_history", None), + lookback_days=int(getattr(mod, "LOOKBACK_DAYS", meta.get("lookback_days", 1)) or 1), + source=source, + file_path=path, + ) + + def reload(self) -> None: + """热重载所有策略""" + self._load_all() + + # ================================================================ + # 查询 + # ================================================================ + + def list_strategies(self) -> list[dict]: + """返回所有策略的元信息""" + result = [] + for s in self._strategies.values(): + result.append({**s.meta, "source": s.source}) + return result + + def get(self, strategy_id: str) -> StrategyDef: + s = self._strategies.get(strategy_id) + if not s: + raise ValueError(f"unknown strategy: {strategy_id}") + return s + + def has(self, strategy_id: str) -> bool: + return strategy_id in self._strategies + + # ================================================================ + # 执行 + # ================================================================ + + def run( + self, + strategy_id: str, + as_of: date, + pool: list[str] | None = None, + params: dict | None = None, + overrides: dict | None = None, + precomputed: pl.DataFrame | None = None, + precomputed_history: pl.DataFrame | None = None, + ) -> StrategyResult: + """执行策略: 基础过滤 → 策略过滤 → 评分排序 + + Args: + strategy_id: 策略 ID + as_of: 选股日期 + pool: 限定股票池 + params: 策略参数 (用户在设置面板调的值) + overrides: 用户覆盖配置 (basic_filter/scoring/stop_loss 等) + precomputed: 已加载的 enriched 数据 (run_all 场景复用) + precomputed_history: 已加载的历史窗口数据 (run_all 场景复用) + """ + t0 = time.perf_counter() + + s = self.get(strategy_id) + params = params or {} + overrides = overrides or {} + + # 加载数据。普通策略只读目标日期;声明 filter_history 的策略读取历史窗口。 + if s.filter_history_fn: + if precomputed_history is not None and not precomputed_history.is_empty(): + df = precomputed_history + elif self._history_loader: + df = self._history_loader(as_of, max(1, s.lookback_days)) + else: + logger.warning("strategy %s requires history loader", strategy_id) + return StrategyResult(as_of=as_of, strategy_id=strategy_id) + if df.is_empty(): + return StrategyResult(as_of=as_of, strategy_id=strategy_id) + df = s.filter_history_fn(df, params) + if df.is_empty(): + return StrategyResult(as_of=as_of, strategy_id=strategy_id) + if "date" in df.columns: + df = df.filter(pl.col("date") == as_of) + elif precomputed is not None and not precomputed.is_empty(): + df = precomputed + else: + df = self._loader(as_of) + if df.is_empty(): + return StrategyResult(as_of=as_of, strategy_id=strategy_id) + + # 基础过滤: 策略默认 basic_filter 兜底, 用户 override 优先覆盖。 + # 这样策略文件里写的 exclude_st/price_min 等默认值即使前端没保存也能生效。 + bf = dict(s.basic_filter) if s.basic_filter else {} + if overrides and overrides.get("basic_filter"): + bf.update(overrides["basic_filter"]) + + # Stage 1: 基础过滤(enabled 默认开启; 显式 enabled=false 才跳过) + if bf and bf.get("enabled", True): + df = self._apply_basic_filter(df, bf) + + # Pool 过滤 + if pool: + df = df.filter(pl.col("symbol").is_in(pool)) + + # Stage 2: 策略过滤 + if s.filter_fn: + expr = s.filter_fn(df, params) + df = df.filter(expr) + + # Stage 3: 评分 + scoring = s.meta.get("scoring", {}) + scoring_overrides = overrides.get("scoring") + if scoring_overrides: + scoring = {**scoring, **scoring_overrides} + df = self._apply_scoring(df, scoring) + + # 排序 + 限制 + limit = s.meta.get("limit", 100) + order_desc = s.meta.get("descending", True) + if "score" in df.columns: + df = df.sort("score", descending=order_desc) + elif s.meta.get("order_by") and s.meta["order_by"] != "score": + ob = s.meta["order_by"] + if ob in df.columns: + df = df.sort(ob, descending=order_desc) + df = df.head(limit) + + # 输出 + rows = _sanitize(df.to_dicts()) + elapsed = (time.perf_counter() - t0) * 1000 + + scores: dict[str, float] = {} + if "score" in df.columns: + for r in df.iter_rows(named=True): + scores[r["symbol"]] = float(r.get("score") or 0) + + return StrategyResult( + as_of=as_of, + strategy_id=strategy_id, + rows=rows, + total=len(rows), + elapsed_ms=elapsed, + scores=scores, + ) + + def run_all(self, as_of: date, params_map: dict | None = None, + overrides_map: dict | None = None) -> dict[str, StrategyResult]: + """批量执行所有策略 (enriched 只加载一次,基础过滤按策略分组缓存,历史数据共享)""" + df = self._loader(as_of) + params_map = params_map or {} + overrides_map = overrides_map or {} + + # 历史策略: 找最大 lookback,一次加载共享 + history_strats = [(sid, s) for sid, s in self._strategies.items() if s.filter_history_fn] + if history_strats and self._history_loader: + max_lookback = max(s.lookback_days for _, s in history_strats) + shared_history = self._history_loader(as_of, max(1, max_lookback)) + else: + shared_history = None + + # 按 basic_filter hash 分组,避免重复过滤 + bf_cache: dict[str, pl.DataFrame] = {} + results: dict[str, StrategyResult] = {} + + for sid, strat in self._strategies.items(): + try: + bf_key = _dict_hash(strat.basic_filter) + if bf_key not in bf_cache: + if strat.basic_filter.get("enabled", True): + bf_cache[bf_key] = self._apply_basic_filter(df, strat.basic_filter) + else: + bf_cache[bf_key] = df + base = bf_cache[bf_key] + + # 从已过滤的 base 执行 (filter_history 策略使用共享历史) + results[sid] = self.run( + sid, as_of, + params=params_map.get(sid), + overrides=overrides_map.get(sid), + precomputed=base, + precomputed_history=shared_history, + ) + except Exception as e: + logger.warning("run strategy %s failed: %s", sid, e) + + return results + + # ================================================================ + # 内部: 基础过滤 + # ================================================================ + + @staticmethod + def _basic_filter_expr(df: pl.DataFrame, bf: dict) -> pl.Expr | None: + """构建基础过滤表达式。回测可复用为买入候选 mask,不删除行情行。""" + exprs: list[pl.Expr] = [] + if bf.get("price_min") is not None: + exprs.append(pl.col("close") >= bf["price_min"]) + if bf.get("price_max") is not None: + exprs.append(pl.col("close") <= bf["price_max"]) + if bf.get("market_cap_min") is not None and "total_shares" in df.columns: + exprs.append( + pl.col("close") * pl.col("total_shares") >= bf["market_cap_min"] + ) + if bf.get("market_cap_max") is not None and "total_shares" in df.columns: + exprs.append( + pl.col("close") * pl.col("total_shares") <= bf["market_cap_max"] + ) + # 流通市值 + if bf.get("float_cap_min") is not None and "float_shares" in df.columns: + exprs.append( + pl.col("close") * pl.col("float_shares") >= bf["float_cap_min"] + ) + if bf.get("float_cap_max") is not None and "float_shares" in df.columns: + exprs.append( + pl.col("close") * pl.col("float_shares") <= bf["float_cap_max"] + ) + if bf.get("amount_min") is not None: + exprs.append(pl.col("amount") >= bf["amount_min"]) + if bf.get("amount_max") is not None: + exprs.append(pl.col("amount") <= bf["amount_max"]) + # 换手率 + if bf.get("turnover_min") is not None and "turnover_rate" in df.columns: + exprs.append(pl.col("turnover_rate") >= bf["turnover_min"]) + if bf.get("turnover_max") is not None and "turnover_rate" in df.columns: + exprs.append(pl.col("turnover_rate") <= bf["turnover_max"]) + if bf.get("exclude_st") and "name" in df.columns: + exprs.append(~pl.col("name").str.contains("(?i)ST|\\*ST|退")) + # 板块过滤 + boards = bf.get("boards") + if boards and isinstance(boards, list) and len(boards) > 0: + board_exprs: list[pl.Expr] = [] + for b in boards: + if b == "沪主板": + board_exprs.append(pl.col("symbol").str.starts_with("60")) + elif b == "深主板": + board_exprs.append( + pl.col("symbol").str.starts_with("00") + | pl.col("symbol").str.starts_with("001") + ) + elif b == "创业板": + board_exprs.append( + pl.col("symbol").str.starts_with("300") + | pl.col("symbol").str.starts_with("301") + ) + elif b == "科创板": + board_exprs.append(pl.col("symbol").str.starts_with("688")) + elif b == "北交所": + board_exprs.append(pl.col("symbol").str.contains(r"\.BJ$")) + if board_exprs: + exprs.append(pl.any_horizontal(board_exprs)) + if exprs: + return pl.all_horizontal(exprs) + return None + + @staticmethod + def _apply_basic_filter(df: pl.DataFrame, bf: dict) -> pl.DataFrame: + """Stage 1: 基础参数过滤""" + expr = StrategyEngine._basic_filter_expr(df, bf) + if expr is not None: + return df.filter(expr) + return df + + # ================================================================ + # 内部: 评分 + # ================================================================ + + @staticmethod + def _apply_scoring(df: pl.DataFrame, weights: dict) -> pl.DataFrame: + """通用评分: min-max 归一化 → 加权求和 → 0~100 分""" + if not weights: + return df + total_weight = sum(weights.values()) + if total_weight <= 0: + return df + + score_parts: list[pl.Expr] = [] + for col, weight in weights.items(): + if col not in df.columns: + continue + w = weight / total_weight + col_min = pl.col(col).min() + col_range = pl.col(col).max() - col_min + normalized = pl.when(col_range > 0).then( + (pl.col(col) - col_min) / col_range + ).otherwise(pl.lit(0.5)) + score_parts.append(normalized * w) + + if not score_parts: + return df + + score_expr = score_parts[0] + for part in score_parts[1:]: + score_expr = score_expr + part + return df.with_columns((score_expr * 100).alias("score")) + + +def _sanitize(rows: list[dict]) -> list[dict]: + for r in rows: + for k, v in list(r.items()): + if isinstance(v, float) and (v != v or abs(v) == float("inf")): + r[k] = None + return rows + + +def _dict_hash(d: dict) -> str: + """用于 basic_filter 分组缓存""" + return str(sorted(d.items())) diff --git a/backend/app/strategy/monitor.py b/backend/app/strategy/monitor.py new file mode 100644 index 0000000..9b5b262 --- /dev/null +++ b/backend/app/strategy/monitor.py @@ -0,0 +1,204 @@ +"""策略实时监控 — 订阅行情更新,检查策略买卖信号和提醒条件。 + +职责: 接收实时行情 DataFrame → 检查监控中策略的信号/提醒 → 推送告警。 +不知道: 策略加载逻辑、AI、API、配置持久化、回测。 +依赖: 外部调用 on_quote_update() 传入实时数据。 +""" +from __future__ import annotations + +import logging +from dataclasses import dataclass, field +from typing import Any, Callable + +import polars as pl + +logger = logging.getLogger(__name__) + + +@dataclass +class StrategyAlert: + """策略告警""" + type: str # "entry" | "exit" | "alert" + strategy_id: str + symbol: str + name: str | None + message: str + price: float | None = None + change_pct: float | None = None + signals: list[str] = field(default_factory=list) + + +class StrategyMonitorService: + """策略实时监控服务""" + + def __init__(self, alert_handler: Callable[[StrategyAlert], None] | None = None): + """ + Args: + alert_handler: 告警回调 (如推 SSE) + """ + self._alert_handler = alert_handler + # strategy_id → 监控配置 + self._watching: dict[str, dict] = {} + + def start(self, strategy_id: str, config: dict) -> None: + """开始监控一个策略 + + config: { + "entry_signals": ["signal_n_day_high", ...], + "exit_signals": ["signal_ma20_breakdown", ...], + "alerts": [{"field": "rsi_14", "op": ">", "value": 80, "message": "..."}], + } + """ + self._watching[strategy_id] = config + logger.info("strategy monitor started: %s", strategy_id) + + def stop(self, strategy_id: str) -> None: + self._watching.pop(strategy_id, None) + logger.info("strategy monitor stopped: %s", strategy_id) + + def stop_all(self) -> None: + self._watching.clear() + + @property + def watching(self) -> dict[str, dict]: + return dict(self._watching) + + def on_quote_update(self, df: pl.DataFrame) -> list[StrategyAlert]: + """行情更新后调用。向量化检查所有监控策略。 + + Args: + df: 实时 enriched 数据 (~5500行) + Returns: + 触发的告警列表 + """ + if not self._watching or df.is_empty(): + return [] + + all_alerts: list[StrategyAlert] = [] + + for strategy_id, cfg in self._watching.items(): + # 买入信号 + entry_sigs = cfg.get("entry_signals", []) + if entry_sigs: + for sym, name, price, pct, hit_sigs in self._check_signals(df, entry_sigs): + alert = StrategyAlert( + type="entry", + strategy_id=strategy_id, + symbol=sym, + name=name, + message=f"买入信号触发", + price=price, + change_pct=pct, + signals=hit_sigs, + ) + all_alerts.append(alert) + self._emit(alert) + + # 卖出信号 + exit_sigs = cfg.get("exit_signals", []) + if exit_sigs: + for sym, name, price, pct, hit_sigs in self._check_signals(df, exit_sigs): + alert = StrategyAlert( + type="exit", + strategy_id=strategy_id, + symbol=sym, + name=name, + message=f"卖出信号触发", + price=price, + change_pct=pct, + signals=hit_sigs, + ) + all_alerts.append(alert) + self._emit(alert) + + # 提醒条件 + for alert_cfg in cfg.get("alerts", []): + for sym, name, price, pct in self._check_alert(df, alert_cfg): + alert = StrategyAlert( + type="alert", + strategy_id=strategy_id, + symbol=sym, + name=name, + message=alert_cfg.get("message", "提醒"), + price=price, + change_pct=pct, + ) + all_alerts.append(alert) + self._emit(alert) + + return all_alerts + + def _emit(self, alert: StrategyAlert) -> None: + if self._alert_handler: + try: + self._alert_handler(alert) + except Exception as e: + logger.warning("alert handler failed: %s", e) + + @staticmethod + def _check_signals( + df: pl.DataFrame, + signals: list[str], + ) -> list[tuple[str, str | None, float | None, float | None, list[str]]]: + """检查信号列,返回 [(symbol, name, price, change_pct, [hit_signals])]。 + 支持内置 signal_ 与自定义 csg_ 前缀。""" + cols = set(df.columns) + resolved: list[tuple[str, str]] = [] # (原值, 列名) + for s in signals: + col = s if (s.startswith("signal_") or s.startswith("csg_")) else f"signal_{s}" + if col in cols: + resolved.append((s, col)) + if not resolved: + return [] + + mask = pl.any_horizontal(pl.col(c).fill_null(False) for _, c in resolved) + hit_df = df.filter(mask) + + results = [] + for row in hit_df.iter_rows(named=True): + sym = row.get("symbol", "") + name = row.get("name") + price = row.get("close") + pct = row.get("change_pct") + hit_sigs = [orig for orig, col in resolved if row.get(col)] + results.append((sym, name, price, pct, hit_sigs)) + return results + + @staticmethod + def _check_alert( + df: pl.DataFrame, + alert: dict, + ) -> list[tuple[str, str | None, float | None, float | None]]: + """检查阈值型提醒条件""" + field = alert.get("field", "") + if field not in df.columns: + return [] + + if "op" in alert: + # 阈值比较 + op = alert["op"] + value = alert["value"] + col = pl.col(field) + ops = { + ">": col > value, + ">=": col >= value, + "<": col < value, + "<=": col <= value, + } + expr = ops.get(op) + if expr is None: + return [] + else: + # 信号列 (布尔) + expr = pl.col(field).fill_null(False) + + hit_df = df.filter(expr) + results = [] + for row in hit_df.iter_rows(named=True): + results.append(( + row.get("symbol", ""), + row.get("name"), + row.get("close"), + row.get("change_pct"), + )) + return results diff --git a/backend/app/strategy/prompt_builder.py b/backend/app/strategy/prompt_builder.py new file mode 100644 index 0000000..896e3ec --- /dev/null +++ b/backend/app/strategy/prompt_builder.py @@ -0,0 +1,65 @@ +"""策略提示词组装器 — 两步定制流程的提示词生成。 + +职责: 加载对应步骤的 Markdown 指南,拼接用户输入,组装 LLM 提示词。 +不知道: LLM 调用、API、前端、引擎执行。 +""" +from __future__ import annotations + +from pathlib import Path + +_DOCS_DIR = Path(__file__).resolve().parent.parent.parent.parent / "docs" +_cache: dict[str, str] = {} + + +def _load_doc(name: str) -> str: + if name not in _cache: + path = _DOCS_DIR / name + _cache[name] = path.read_text(encoding="utf-8") if path.exists() else "" + return _cache[name] + + +DIRECTION_CN = {"long": "做多", "short": "做空", "monitor": "监控"} + + +def build_step1(name: str, description: str, direction: str, rules: str, strategy_id: str = "") -> str: + """步骤1:规则 → 完整策略代码(参数 + 信号 + 评分 + 告警) + + 注意: strategy-guide.md 已在 ai_generator.py 的 system prompt 中加载, + 此处不再重复加载以节省 token。 + """ + guide = _load_doc("strategy-builder-step1.md") + + id_line = f"\n策略ID(必须使用此ID):{strategy_id}" if strategy_id else "" + + return f"""{guide} + +--- + +请根据以下用户输入生成完整策略代码: + +策略名称:{name}{id_line} +策略描述:{description} +选股方向:{DIRECTION_CN.get(direction, direction)} +策略规则: +{rules} + +只输出 Python 代码。""" + + +def build_step2(current_code: str, instruction: str) -> str: + """步骤2:修改策略任意部分""" + guide = _load_doc("strategy-builder-step2.md") + + return f"""{guide} + +--- + +当前策略代码: +```python +{current_code} +``` + +用户修改指令: +{instruction} + +只输出修改后的完整 Python 代码。""" diff --git a/backend/app/tickflow/__init__.py b/backend/app/tickflow/__init__.py new file mode 100644 index 0000000..ff7675d --- /dev/null +++ b/backend/app/tickflow/__init__.py @@ -0,0 +1 @@ +"""TickFlow 适配层 — 能力探测 / 调度 / Repository。""" diff --git a/backend/app/tickflow/capabilities.py b/backend/app/tickflow/capabilities.py new file mode 100644 index 0000000..7bee5e2 --- /dev/null +++ b/backend/app/tickflow/capabilities.py @@ -0,0 +1,75 @@ +"""Capability 定义(§5.1)。 + +业务代码只依赖 CapabilitySet,不读 tiers.yaml,不感知"档位"。 +""" +from __future__ import annotations + +from dataclasses import dataclass +from enum import StrEnum + + +class Cap(StrEnum): + """所有 capability 的命名常量。新增能力时只在这里加一行。""" + + QUOTE_BY_SYMBOL = "quote.by_symbol" + QUOTE_BATCH = "quote.batch" + QUOTE_POOL = "quote.pool" + KLINE_DAILY_BY_SYMBOL = "kline.daily.by_symbol" + KLINE_DAILY_BATCH = "kline.daily.batch" + KLINE_MINUTE_BY_SYMBOL = "kline.minute.by_symbol" + KLINE_MINUTE_BATCH = "kline.minute.batch" + INTRADAY = "intraday" + INTRADAY_BATCH = "intraday.batch" + DEPTH5 = "depth5" + WEBSOCKET = "websocket" + FINANCIAL = "financial" + ADJ_FACTOR = "adj_factor" + + +@dataclass(slots=True, frozen=True) +class CapabilityLimits: + """单个 capability 的运行时限制。""" + rpm: int | None = None # 次/分钟,None 表示未知或不限 + batch: int | None = None # 标的/次 + subscribe: int | None = None # WS 订阅上限 + + +class CapabilitySet: + """探测得到的"用户当前可用能力"。业务代码的唯一真理源。""" + + def __init__(self, caps: dict[Cap, CapabilityLimits] | None = None) -> None: + self._caps: dict[Cap, CapabilityLimits] = dict(caps or {}) + + def has(self, cap: Cap) -> bool: + return cap in self._caps + + def limits(self, cap: Cap) -> CapabilityLimits | None: + return self._caps.get(cap) + + def require(self, cap: Cap) -> CapabilityLimits: + """断言可用,否则抛 CapabilityDenied。""" + if cap not in self._caps: + raise CapabilityDenied(cap) + return self._caps[cap] + + def all(self) -> dict[Cap, CapabilityLimits]: + return dict(self._caps) + + def to_dict(self) -> dict[str, dict]: + return { + str(cap): { + "rpm": lim.rpm, + "batch": lim.batch, + "subscribe": lim.subscribe, + } + for cap, lim in self._caps.items() + } + + +class CapabilityDenied(Exception): + """请求的 capability 当前不可用。""" + + def __init__(self, cap: Cap, suggestion: str | None = None) -> None: + self.cap = cap + self.suggestion = suggestion or f"加购『{cap}』能力可解锁" + super().__init__(f"capability not available: {cap}; {self.suggestion}") diff --git a/backend/app/tickflow/client.py b/backend/app/tickflow/client.py new file mode 100644 index 0000000..4351bf4 --- /dev/null +++ b/backend/app/tickflow/client.py @@ -0,0 +1,72 @@ +"""TickFlow SDK 封装(§5)。 + +进程内单例;Key 来源(优先级):secrets.json > .env。 +用户改 Key 后需要 `reset_clients()`,然后 `get_client()` 会拿新的。 +""" +from __future__ import annotations + +import os + +from tickflow import AsyncTickFlow, TickFlow + +from app import secrets_store + +_sync_client: TickFlow | None = None +_async_client: AsyncTickFlow | None = None + + +def _base_url() -> str | None: + """从 secrets.json 读取用户自定义端点,没有则返回 None(用 SDK 默认)。""" + return secrets_store.load().get("tickflow_base_url") or None + + +def get_client() -> TickFlow: + """同步客户端。能力探测、盘后管道用。""" + global _sync_client + if _sync_client is None: + key = secrets_store.get_tickflow_key() + if not key: + # Free 模式:付费端点 URL 不可用,忽略 base_url 走 SDK 默认 free-api + _sync_client = TickFlow.free() + else: + _sync_client = TickFlow(api_key=key, base_url=_base_url()) + return _sync_client + + +def get_async_client() -> AsyncTickFlow: + """异步客户端。FastAPI 请求路径上用。""" + global _async_client + if _async_client is None: + key = secrets_store.get_tickflow_key() + if not key: + # Free 模式:付费端点 URL 不可用,忽略 base_url 走 SDK 默认 free-api + _async_client = AsyncTickFlow.free() + else: + _async_client = AsyncTickFlow(api_key=key, base_url=_base_url()) + return _async_client + + +def reset_clients() -> None: + """Key 变化后调用 — 让下一次 get_client() 拿新实例。""" + global _sync_client, _async_client + _sync_client = None + _async_client = None + + +def current_mode() -> str: + """供 UI 显示当前模式。""" + return "api_key" if secrets_store.get_tickflow_key() else "free" + + +def current_endpoint() -> str: + """返回当前显示用的端点 URL(对应 endpoints.json 列表项)。 + + 注:SDK 的 TickFlow.free() 内部实际走 free-api,但 UI 显示统一用默认 + 节点(api.tickflow.org),使"当前使用"始终对得上端点列表里的某一项。 + """ + # 自定义端点(付费模式测速切换后):优先返回 + base = _base_url() + if base: + return base.rstrip("/") + # Free 模式或未自定义:统一显示默认节点 + return "https://api.tickflow.org" diff --git a/backend/app/tickflow/policy.py b/backend/app/tickflow/policy.py new file mode 100644 index 0000000..3307408 --- /dev/null +++ b/backend/app/tickflow/policy.py @@ -0,0 +1,390 @@ +"""能力探测 + CapabilitySet 持久化(§5.3)。 + +探测策略:逐 capability 用最小代价请求试探。 + - 成功 → 记录可用,优先取响应头 X-RateLimit-* 否则用 tiers.yaml 默认 + - 抛权限错 → 不可用 + - 抛其他错 → 不可用(谨慎,保留日志) + +Tier Label 算法见 §5.3:基线档 + 补丁能力。 +""" +from __future__ import annotations + +import json +import logging +from pathlib import Path +from typing import Any + +import yaml + +from app.config import settings + +from .capabilities import Cap, CapabilityLimits, CapabilitySet + +logger = logging.getLogger(__name__) + +_CAPSET_CACHE_FILE = "capabilities.json" + +# 探测用最小代价请求:挑流通性最好的 1 只标的试 +_PROBE_SYMBOL = "600000.SH" # 浦发银行,长期不会退市 + + +def _load_tiers_yaml() -> dict[str, dict[str, dict[str, Any]]]: + for path in [settings.tiers_yaml, Path("/app/tiers.yaml"), Path("../tiers.yaml")]: + if path.exists(): + with path.open(encoding="utf-8") as f: + return yaml.safe_load(f) + raise FileNotFoundError("tiers.yaml not found") + + +def _tier_to_capset(tier_def: dict[str, dict[str, Any]]) -> CapabilitySet: + caps: dict[Cap, CapabilityLimits] = {} + for cap_name, limits_dict in tier_def.items(): + try: + cap = Cap(cap_name) + except ValueError: + logger.warning("unknown cap in tiers.yaml: %s", cap_name) + continue + caps[cap] = CapabilityLimits( + rpm=limits_dict.get("rpm"), + batch=limits_dict.get("batch"), + subscribe=limits_dict.get("subscribe"), + ) + return CapabilitySet(caps) + + +def _probe_real(tiers: dict) -> tuple[CapabilitySet, list[str]]: + """逐 capability 试探。需要 API key。 + + 返回 (capset, probe_log)。 + """ + from .client import get_client + + tf = get_client() + available: dict[Cap, CapabilityLimits] = {} + log: list[str] = [] + + def try_call(cap: Cap, fn, default_limits: dict[str, Any]) -> None: + try: + fn() + available[cap] = CapabilityLimits( + rpm=default_limits.get("rpm"), + batch=default_limits.get("batch"), + subscribe=default_limits.get("subscribe"), + ) + log.append(f"✓ {cap}") + except Exception as e: # noqa: BLE001 + msg = str(e).lower() + cls = e.__class__.__name__ + # PermissionError 类名 / HTTP 403 / 中英文权限关键词都算"明确无权限" + is_perm_denied = ( + cls in {"PermissionError", "AuthorizationError"} + or "permission" in msg or "unauthorized" in msg + or "403" in msg or "forbidden" in msg + or "套餐" in msg or "权限" in msg or "需要" in msg + ) + if is_perm_denied: + log.append(f"✗ {cap}(无权限)") + else: + log.append(f"? {cap} ({cls}: {e})") + + # 用各档默认上限作为占位(无 X-RateLimit-* 头时) + # 取所有档的并集,逐 cap 试探 + all_caps_defaults: dict[str, dict[str, Any]] = {} + for tier in ("free", "starter", "pro", "expert"): + for cap_name, lim in tiers.get(tier, {}).items(): + all_caps_defaults.setdefault(cap_name, lim) + + def defaults(cap: Cap) -> dict[str, Any]: + return all_caps_defaults.get(str(cap), {}) + + # 全部用 keyword-only 形式调用,符合 SDK 真实签名 + # quote.by_symbol + try_call(Cap.QUOTE_BY_SYMBOL, + lambda: tf.quotes.get(symbols=[_PROBE_SYMBOL], as_dataframe=False), + defaults(Cap.QUOTE_BY_SYMBOL)) + + # quote.pool — 用一个真实存在的 universe id 试探。 + # universes.list() 在 Free 也开放,先拿任意一个 universe id 再用 get_by_universes 试。 + def _probe_pool(): + unis = tf.universes.list() + if not unis: + raise RuntimeError("no universes available") + first_id = unis[0]["id"] if isinstance(unis[0], dict) else getattr(unis[0], "id") + return tf.quotes.get_by_universes([first_id], as_dataframe=False) + + try_call(Cap.QUOTE_POOL, _probe_pool, defaults(Cap.QUOTE_POOL)) + + # kline.daily.by_symbol — Free 也有 + try_call(Cap.KLINE_DAILY_BY_SYMBOL, + lambda: tf.klines.get(_PROBE_SYMBOL, period="1d", count=1, as_dataframe=False), + defaults(Cap.KLINE_DAILY_BY_SYMBOL)) + + # kline.daily.batch + try_call(Cap.KLINE_DAILY_BATCH, + lambda: tf.klines.batch([_PROBE_SYMBOL], period="1d", count=1, as_dataframe=False), + defaults(Cap.KLINE_DAILY_BATCH)) + + # kline.minute.by_symbol + try_call(Cap.KLINE_MINUTE_BY_SYMBOL, + lambda: tf.klines.get(_PROBE_SYMBOL, period="1m", count=1, as_dataframe=False), + defaults(Cap.KLINE_MINUTE_BY_SYMBOL)) + + # kline.minute.batch + try_call(Cap.KLINE_MINUTE_BATCH, + lambda: tf.klines.batch([_PROBE_SYMBOL], period="1m", count=1, as_dataframe=False), + defaults(Cap.KLINE_MINUTE_BATCH)) + + # intraday + try_call(Cap.INTRADAY, + lambda: tf.klines.intraday(_PROBE_SYMBOL, count=1, as_dataframe=False), + defaults(Cap.INTRADAY)) + + # intraday.batch + try_call(Cap.INTRADAY_BATCH, + lambda: tf.klines.intraday_batch([_PROBE_SYMBOL], count=1, as_dataframe=False), + defaults(Cap.INTRADAY_BATCH)) + + # depth5 + try_call(Cap.DEPTH5, + lambda: tf.depth.get(_PROBE_SYMBOL), + defaults(Cap.DEPTH5)) + + # financial — SDK 提供 income / balance_sheet / cash_flow / metrics / shares + # 用 metrics 探测(单据最小) + try_call(Cap.FINANCIAL, + lambda: tf.financials.metrics([_PROBE_SYMBOL], latest=True, as_dataframe=False), + defaults(Cap.FINANCIAL)) + + # adj_factor — 实际在 klines.ex_factors + try_call(Cap.ADJ_FACTOR, + lambda: tf.klines.ex_factors([_PROBE_SYMBOL], as_dataframe=False), + defaults(Cap.ADJ_FACTOR)) + + # websocket 不在探测期试连接(成本太高且阻塞),按档位默认推断 + # 若 expert 的其他 cap 都通,则推断 websocket 也可用 + if (Cap.FINANCIAL in available and Cap.INTRADAY_BATCH in available): + available[Cap.WEBSOCKET] = CapabilityLimits( + subscribe=defaults(Cap.WEBSOCKET).get("subscribe", 100), + ) + log.append("✓ websocket (inferred from expert tier)") + + return CapabilitySet(available), log + + +def detect_capabilities(force: bool = False) -> CapabilitySet: + """探测当前 API Key 的能力集。""" + cache_path = settings.data_dir / _CAPSET_CACHE_FILE + if not force and cache_path.exists(): + with cache_path.open(encoding="utf-8") as f: + cached = json.load(f) + return _capset_from_json(cached) + + tiers = _load_tiers_yaml() + if settings.use_free_mode: + capset = _tier_to_capset(tiers["free"]) + label, missing, extras = _compute_label_and_missing(capset, tiers) + _persist(capset, label, log=["Free 模式(无 API Key)"], missing=missing, extras=extras) + return capset + + # 有 API key — 真实探测 + try: + capset, probe_log = _probe_real(tiers) + if not capset.all(): + logger.warning("probe returned no caps; falling back to free baseline") + capset = _tier_to_capset(tiers["free"]) + probe_log.append("⚠ 所有探测均失败,降级为 Free 占位") + label, missing, extras = _compute_label_and_missing(capset, tiers) + # 探测时 limits 用了"任意档默认值",现在判档完成,用真实档位的 limits 覆盖 + capset = _override_limits_with_detected_tier(capset, label, tiers) + _persist(capset, label, log=probe_log, missing=missing, extras=extras) + return capset + except Exception as e: + logger.exception("detect_capabilities failed; using free baseline: %s", e) + capset = _tier_to_capset(tiers["free"]) + _persist(capset, "Free(探测失败)", log=[f"探测失败:{e}"], missing=[], extras=[]) + return capset + + +# ===== Tier 代表性 capability(signature caps)===== +# 拥有**任意一个**即认作该档及以上。自上而下匹配。 +# 这套设计的好处:单个 capability 探测的 transient 失败不会把整体档位"误降"。 +TIER_SIGNATURES: dict[str, set[Cap]] = { + "expert": {Cap.FINANCIAL, Cap.INTRADAY_BATCH, Cap.WEBSOCKET}, + "pro": {Cap.KLINE_MINUTE_BATCH, Cap.KLINE_MINUTE_BY_SYMBOL, + Cap.INTRADAY, Cap.DEPTH5}, + "starter": {Cap.QUOTE_BATCH, Cap.KLINE_DAILY_BATCH, + Cap.ADJ_FACTOR, Cap.QUOTE_POOL}, + # free 不需 signature — 默认兜底 +} + +# 补丁友好命名(label 后缀用) +_CAP_ALIASES: dict[Cap, str] = { + Cap.KLINE_MINUTE_BATCH: "分钟K", + Cap.KLINE_MINUTE_BY_SYMBOL: "分钟K", + Cap.INTRADAY: "分时", + Cap.INTRADAY_BATCH: "批量分时", + Cap.DEPTH5: "五档", + Cap.WEBSOCKET: "WS", + Cap.FINANCIAL: "财务", + Cap.ADJ_FACTOR: "复权", + Cap.QUOTE_BATCH: "批量行情", + Cap.QUOTE_POOL: "标的池", + Cap.KLINE_DAILY_BATCH: "日K批量", +} + + +def _override_limits_with_detected_tier( + capset: CapabilitySet, label: str, tiers: dict, +) -> CapabilitySet: + """探测完成后,用判档对应的 limits 覆盖每个 cap 的速率/批量。 + + 判档前每个 cap 用的是"所有档默认值的并集"(为了不漏数据), + 判档后才知道用户真实档位,limits 用该档的实际值更准。 + label 可能是 "Pro" / "Pro + 分钟K" / "Pro+" 等组合形式 — 取第一个词当作基线档名。 + """ + base_name = label.split()[0].split("+")[0].strip().lower() # "Pro + 分钟K" → "pro" + tier_limits = tiers.get(base_name, {}) + new_caps: dict[Cap, CapabilityLimits] = {} + for cap, _old_lim in capset.all().items(): + spec = tier_limits.get(cap.value) + if spec: + new_caps[cap] = CapabilityLimits( + rpm=spec.get("rpm"), + batch=spec.get("batch"), + subscribe=spec.get("subscribe"), + ) + else: + # 不在该档定义里(extras),用 expert 档兜底(最宽松) + expert_spec = tiers.get("expert", {}).get(cap.value, {}) + new_caps[cap] = CapabilityLimits( + rpm=expert_spec.get("rpm"), + batch=expert_spec.get("batch"), + subscribe=expert_spec.get("subscribe"), + ) + return CapabilitySet(new_caps) + + +def _tier_caps_set(tiers: dict, tier_name: str) -> set[Cap]: + """读 tiers.yaml 的某档定义,转为 Cap 集合。""" + return {Cap(c) for c in tiers.get(tier_name, {}).keys() if c in {x.value for x in Cap}} + + +def _compute_label_and_missing( + capset: CapabilitySet, tiers: dict, +) -> tuple[str, list[str], list[str]]: + """返回 (label, missing_caps, extra_caps)。 + + label:档位标签。 + missing_caps:本档**应有但未探测到**的 capability(用于诊断:可能是探测 bug 或权限丢失)。 + extra_caps:超出本档的额外 capability(自定义组合)。 + """ + held = set(capset.all().keys()) + + # 1) 完全匹配 — 干净命中某档 + for tier_name in ["free", "starter", "pro", "expert"]: + if held == _tier_caps_set(tiers, tier_name): + return tier_name.capitalize(), [], [] + + # 2) 按 signature 自上而下判档 + if held & TIER_SIGNATURES["expert"]: + base = "expert" + elif held & TIER_SIGNATURES["pro"]: + base = "pro" + elif held & TIER_SIGNATURES["starter"]: + base = "starter" + else: + base = "free" + + base_caps = _tier_caps_set(tiers, base) + missing = sorted(c.value for c in (base_caps - held)) + extras = base_caps and (held - base_caps) or set() # extras 是超出该档的部分 + + # 实际超出 = held 中"既不属于本档、也不属于本档下方任何档"的 cap + # 简化:extras = held - base_caps + extras_set = held - base_caps + + # 3) 拼 label + if not extras_set: + # 完全在本档内(可能缺一两项 — 由 missing 反映) + return base.capitalize(), missing, [] + + # 补丁过多 → 用 "≈" 形式 + if len(extras_set) > 3: + return f"{base.capitalize()}+", missing, sorted(c.value for c in extras_set) + + suffix = sorted({_CAP_ALIASES.get(e, str(e)) for e in extras_set}) + return f"{base.capitalize()} + " + " + ".join(suffix), missing, sorted(c.value for c in extras_set) + + +def _compute_label(capset: CapabilitySet, tiers: dict) -> str: + """对外简化签名 — 只要 label。""" + label, _missing, _extras = _compute_label_and_missing(capset, tiers) + return label + + +def _persist( + capset: CapabilitySet, + label: str, + log: list[str] | None = None, + missing: list[str] | None = None, + extras: list[str] | None = None, +) -> None: + settings.data_dir.mkdir(parents=True, exist_ok=True) + cache_path = settings.data_dir / _CAPSET_CACHE_FILE + payload = { + "label": label, + "capabilities": capset.to_dict(), + "probe_log": log or [], + "missing_caps": missing or [], # 本档应有但未探测到 + "extras_caps": extras or [], # 超出本档的额外能力 + } + with cache_path.open("w", encoding="utf-8") as f: + json.dump(payload, f, ensure_ascii=False, indent=2) + + +def _capset_from_json(data: dict[str, Any]) -> CapabilitySet: + caps: dict[Cap, CapabilityLimits] = {} + for cap_name, lim in data.get("capabilities", {}).items(): + try: + cap = Cap(cap_name) + except ValueError: + continue + caps[cap] = CapabilityLimits( + rpm=lim.get("rpm"), + batch=lim.get("batch"), + subscribe=lim.get("subscribe"), + ) + return CapabilitySet(caps) + + +def tier_label() -> str: + cache_path = settings.data_dir / _CAPSET_CACHE_FILE + if cache_path.exists(): + with cache_path.open(encoding="utf-8") as f: + return json.load(f).get("label", "Unknown") + return "Unknown" + + +def probe_log() -> list[str]: + cache_path = settings.data_dir / _CAPSET_CACHE_FILE + if cache_path.exists(): + with cache_path.open(encoding="utf-8") as f: + return json.load(f).get("probe_log", []) + return [] + + +def missing_caps() -> list[str]: + """本档应有但未探测到的 capability — 通常意味着探测有 bug 或权限边界。""" + cache_path = settings.data_dir / _CAPSET_CACHE_FILE + if cache_path.exists(): + with cache_path.open(encoding="utf-8") as f: + return json.load(f).get("missing_caps", []) + return [] + + +def extras_caps() -> list[str]: + cache_path = settings.data_dir / _CAPSET_CACHE_FILE + if cache_path.exists(): + with cache_path.open(encoding="utf-8") as f: + return json.load(f).get("extras_caps", []) + return [] diff --git a/backend/app/tickflow/pools.py b/backend/app/tickflow/pools.py new file mode 100644 index 0000000..77a45d9 --- /dev/null +++ b/backend/app/tickflow/pools.py @@ -0,0 +1,158 @@ +"""标的池(Universe)定义(§6.3)。 + +Phase 1 实现: + - 常用指数成份(沪深 300 / 中证 500 / 上证 50)用 TickFlow `quote.pool` 端点拉取并缓存 + - 全 A 通过 instruments.batch 获取 + - 自选池 = 用户的 watchlist +""" +from __future__ import annotations + +import logging +from datetime import date +from pathlib import Path +from typing import Literal + +import polars as pl + +from app.config import settings +from app.tickflow.client import get_client + +logger = logging.getLogger(__name__) + +PoolId = Literal["CSI300", "CSI500", "SSE50", "CN_Equity_A", "CN_Index", "watchlist"] + +# TickFlow universe id 是它内部命名(见 tf.universes.list())。 +# 没有官方对照表,启动时按名称模糊匹配从 universes.list() 里找。 +# 常见名:沪深300 / 中证500 / 上证50 / 全 A +_POOL_NAME_HINTS = { + "CSI300": ["沪深300", "HS300", "CSI300"], + "CSI500": ["中证500", "ZZ500", "CSI500"], + "SSE50": ["上证50", "SH50", "SSE50"], +} + + +def _find_universe_id(hints: list[str]) -> str | None: + """从 universes.list() 里按 name/id 子串匹配找一个 universe id。""" + try: + tf = get_client() + unis = tf.universes.list() + except Exception as e: # noqa: BLE001 + logger.warning("universes.list failed: %s", e) + return None + for u in unis or []: + item = u if isinstance(u, dict) else {"id": getattr(u, "id", ""), "name": getattr(u, "name", "")} + haystack = (item.get("id", "") + " " + item.get("name", "")).lower() + for h in hints: + if h.lower() in haystack: + return item["id"] + return None + + +def _pool_cache_path(pool_id: str) -> Path: + return settings.data_dir / "pools" / f"{pool_id}.parquet" + + +def get_pool(pool_id: PoolId, refresh: bool = False) -> list[str]: + """返回标的池里的 symbol 列表。""" + if pool_id == "watchlist": + return _load_watchlist() + + cache = _pool_cache_path(pool_id) + if cache.exists() and not refresh: + df = pl.read_parquet(cache) + return df["symbol"].to_list() + + symbols = _fetch_pool(pool_id) + if symbols: + cache.parent.mkdir(parents=True, exist_ok=True) + pl.DataFrame({"symbol": symbols, "as_of": [date.today()] * len(symbols)}).write_parquet(cache) + return symbols + + +def _fetch_pool(pool_id: PoolId) -> list[str]: + """从 TickFlow 拉取池成份。 + + 实现:先用 universes.list 找到 universe id,再 quotes.get_by_universes 拉成份。 + """ + tf = get_client() + + if pool_id in _POOL_NAME_HINTS: + uid = _find_universe_id(_POOL_NAME_HINTS[pool_id]) + if not uid: + logger.warning("无法在 TickFlow universes 列表里匹配到 %s", pool_id) + return [] + try: + df = tf.quotes.get_by_universes([uid], as_dataframe=True) + if df is not None and len(df) > 0 and "symbol" in df.columns: + return df["symbol"].astype(str).tolist() + except Exception as e: # noqa: BLE001 + logger.warning("fetch pool %s via universe %s failed: %s", pool_id, uid, e) + + if pool_id == "CN_Equity_A": + # 全 A — 优先直接用 CN_Equity_A universe (包含沪深京三市) + uid = _find_universe_id(["CN_Equity_A", "沪深京A股", "全A"]) + if uid: + try: + df = tf.quotes.get_by_universes([uid], as_dataframe=True) + if df is not None and len(df) > 0 and "symbol" in df.columns: + return sorted(set(df["symbol"].astype(str).tolist())) + except Exception as e: # noqa: BLE001 + logger.warning("fetch CN_Equity_A via universe %s failed: %s", uid, e) + + # fallback: 聚合申万一级行业 (覆盖度较低, 缺北交所/新股) + try: + unis = tf.universes.list() + except Exception as e: # noqa: BLE001 + logger.warning("universes.list failed: %s", e) + unis = [] + sw1_ids = [] + for u in unis or []: + item = u if isinstance(u, dict) else {"id": getattr(u, "id", "")} + uid = item.get("id", "") + if "SW1_" in uid: + sw1_ids.append(uid) + if sw1_ids: + try: + df = tf.quotes.get_by_universes(sw1_ids, as_dataframe=True) + if df is not None and "symbol" in df.columns: + return sorted(set(df["symbol"].astype(str).tolist())) + except Exception as e: # noqa: BLE001 + logger.warning("aggregate SW1 fetch failed: %s", e) + + if pool_id == "CN_Index": + uid = _find_universe_id(["CN_Index", "沪深指数", "指数"]) + ids = [uid] if uid else ["CN_Index"] + try: + df = tf.quotes.get_by_universes(ids, as_dataframe=True) + if df is not None and len(df) > 0 and "symbol" in df.columns: + return sorted(set(df["symbol"].astype(str).tolist())) + except Exception as e: # noqa: BLE001 + logger.warning("fetch CN_Index via universe %s failed: %s", ids, e) + + return [] + + +def _load_watchlist() -> list[str]: + """读取用户自选(由 watchlist service 维护)。""" + path = settings.data_dir / "user_data" / "watchlist.parquet" + if not path.exists(): + return [] + df = pl.read_parquet(path) + if df.is_empty() or "symbol" not in df.columns: + return [] + return df["symbol"].to_list() + + +# 兜底:Free 用户/无 API 时给一个小型可用集合,让 UI 不至于空白 +DEMO_SYMBOLS = [ + "600000.SH", # 浦发银行 + "600036.SH", # 招商银行 + "600519.SH", # 贵州茅台 + "601318.SH", # 中国平安 + "601398.SH", # 工商银行 + "000001.SZ", # 平安银行 + "000333.SZ", # 美的集团 + "000651.SZ", # 格力电器 + "000858.SZ", # 五粮液 + "002594.SZ", # 比亚迪 +] diff --git a/backend/app/tickflow/repository.py b/backend/app/tickflow/repository.py new file mode 100644 index 0000000..9c2f630 --- /dev/null +++ b/backend/app/tickflow/repository.py @@ -0,0 +1,965 @@ +"""Repository 层(§7.4)。 + +数据分层: + - DuckDB 视图: 冷查询(统计、元数据、用户自定义SQL) + - Polars 缓存: 热路径(enriched 最新日 ~5500行 + instruments ~5500行) + - Polars scan_parquet: 分钟K/历史日K (predicate pushdown) + +缓存生命周期: + - startup 时不加载(数据可能为空) + - pipeline 完成后调用 refresh_cache() + - 服务层通过 get_enriched_latest() / get_instruments() 获取缓存 +""" +from __future__ import annotations + +import logging +import threading +from datetime import date +from pathlib import Path + +import duckdb +import polars as pl + +from app.config import settings + +logger = logging.getLogger(__name__) + + +class DataStore: + """唯一的存储入口 — 进程启动时创建。""" + + def __init__(self, data_dir: Path | None = None) -> None: + self.data_dir = Path(data_dir or settings.data_dir) + self.data_dir.mkdir(parents=True, exist_ok=True) + + # 关键子目录(§7.2) + for sub in ( + "kline_daily", + "kline_daily_enriched", + "kline_index_daily", + "kline_index_enriched", + "kline_minute", + "adj_factor", + "financials", + "instruments", + "instruments_index", + "instruments_ext", + "kline_ext", + "pools", + "backtest_results", + "screener_results", + "ai_cache", + "user_data", + ): + (self.data_dir / sub).mkdir(parents=True, exist_ok=True) + + # 财务数据子目录 + for sub in ("metrics", "income", "balance_sheet", "cash_flow"): + (self.data_dir / "financials" / sub).mkdir(parents=True, exist_ok=True) + + # DuckDB 内存模式 — 不建 .db 文件(§7.1) + self.db = duckdb.connect(database=":memory:") + self._register_views() + + def _register_views(self) -> None: + """把 Parquet 目录挂载为 DuckDB 视图(§7.3)。""" + d = self.data_dir.as_posix() + statements = [ + f"""CREATE OR REPLACE VIEW kline_daily AS + SELECT * FROM read_parquet('{d}/kline_daily/**/*.parquet', union_by_name=true)""", + f"""CREATE OR REPLACE VIEW kline_enriched AS + SELECT * FROM read_parquet('{d}/kline_daily_enriched/**/*.parquet', union_by_name=true)""", + f"""CREATE OR REPLACE VIEW kline_index_daily AS + SELECT * FROM read_parquet('{d}/kline_index_daily/**/*.parquet', union_by_name=true)""", + f"""CREATE OR REPLACE VIEW kline_index_enriched AS + SELECT * FROM read_parquet('{d}/kline_index_enriched/**/*.parquet', union_by_name=true)""", + f"""CREATE OR REPLACE VIEW kline_minute AS + SELECT * FROM read_parquet('{d}/kline_minute/**/*.parquet', union_by_name=true)""", + f"""CREATE OR REPLACE VIEW adj_factor AS + SELECT * FROM read_parquet('{d}/adj_factor/**/*.parquet', union_by_name=true)""", + f"""CREATE OR REPLACE VIEW instruments AS + SELECT * FROM read_parquet('{d}/instruments/**/*.parquet', union_by_name=true)""", + f"""CREATE OR REPLACE VIEW instruments_index AS + SELECT * FROM read_parquet('{d}/instruments_index/**/*.parquet', union_by_name=true)""", + f"""CREATE OR REPLACE VIEW instruments_ext AS + SELECT * FROM read_parquet('{d}/instruments_ext/**/*.parquet', union_by_name=true)""", + f"""CREATE OR REPLACE VIEW kline_ext AS + SELECT * FROM read_parquet('{d}/kline_ext/**/*.parquet', union_by_name=true)""", + # 财务数据视图 + f"""CREATE OR REPLACE VIEW financials_metrics AS + SELECT * FROM read_parquet('{d}/financials/metrics/*.parquet', union_by_name=true)""", + f"""CREATE OR REPLACE VIEW financials_income AS + SELECT * FROM read_parquet('{d}/financials/income/*.parquet', union_by_name=true)""", + f"""CREATE OR REPLACE VIEW financials_balance_sheet AS + SELECT * FROM read_parquet('{d}/financials/balance_sheet/*.parquet', union_by_name=true)""", + f"""CREATE OR REPLACE VIEW financials_cash_flow AS + SELECT * FROM read_parquet('{d}/financials/cash_flow/*.parquet', union_by_name=true)""", + ] + for sql in statements: + try: + self.db.execute(sql) + except duckdb.IOException: + logger.debug("view registration skipped (no parquet yet): %s", sql[:60]) + + +class KlineRepository: + """日 K / 分钟 K 的读写入口。""" + + def __init__(self, store: DataStore) -> None: + self.store = store + self.db = store.db + self._lock = threading.Lock() + + # ---- Polars 缓存 ---- + self._enriched_cache: pl.DataFrame | None = None # 最新一天 (~5500行) + self._enriched_cache_date: date | None = None + self._live_agg_cache: pl.DataFrame | None = None # 预计算聚合表 (~5500行) + self._live_agg_cache_date: date | None = None + self._instruments_cache: pl.DataFrame | None = None + # 完整 enriched 历史 (含所有指标, 供 filter_history 策略使用) + self._enriched_history_cache: pl.DataFrame | None = None # ~100万行 + self._enriched_history_start: date | None = None + self._index_instruments_cache: pl.DataFrame | None = None + + # parquet glob 路径 + self._enriched_glob = str(store.data_dir / "kline_daily_enriched" / "**" / "*.parquet") + self._index_enriched_glob = str(store.data_dir / "kline_index_enriched" / "**" / "*.parquet") + self._minute_glob = str(store.data_dir / "kline_minute" / "**" / "*.parquet") + self._inst_glob = str(store.data_dir / "instruments" / "**" / "*.parquet") + self._index_inst_glob = str(store.data_dir / "instruments_index" / "**" / "*.parquet") + + def execute_all(self, sql: str, params: list | None = None) -> list[tuple]: + """线程安全的 SELECT → fetchall。DuckDB 单 connection 非线程安全,所有读路径须走此方法。""" + with self._lock: + return self.db.execute(sql, params or []).fetchall() + + def execute_one(self, sql: str, params: list | None = None) -> tuple | None: + """线程安全的 SELECT → fetchone。""" + with self._lock: + return self.db.execute(sql, params or []).fetchone() + + # ================================================================ + # Polars 缓存管理 + # ================================================================ + + def refresh_cache(self) -> None: + """刷新 Polars 缓存。在 pipeline 完成后、服务启动时调用。""" + self._refresh_instruments() + self._refresh_index_instruments() + self._refresh_enriched() + + def _refresh_enriched(self) -> None: + """从 parquet 加载 enriched 最新日到内存 + 构建聚合表。 + + enriched parquet 仅存 14 列基础数据。启动时读入历史数据并即时计算完整指标, + 将结果缓存在内存中供各服务使用。 + + 优化: 扩大历史读取范围, 同时缓存完整历史 (含指标), 供 filter_history 策略直接复用。 + """ + try: + latest = self._latest_enriched_date_duckdb() + if not latest: + return + + # Step 1: 直接读最新日期的分区文件 (仅 14 列) + enriched_dir = self.store.data_dir / "kline_daily_enriched" + ds = latest.isoformat() if hasattr(latest, "isoformat") else str(latest) + target_parquet = enriched_dir / f"date={ds}" / "part.parquet" + + if not target_parquet.exists(): + return + + df_latest = pl.read_parquet(target_parquet) + if df_latest.is_empty(): + return + + # Step 2: 读近 300 天 14 列数据 → compute → filter(latest) → 缓存 + # 300 日历天 ≈ 210 交易日, 覆盖 filter_history 最大 lookback(90) + warmup(60) + try: + from datetime import timedelta + from app.indicators.pipeline import compute_indicators, compute_signals, compute_limit_signals + start_full = latest - timedelta(days=300) + read_cols = [c for c in ["symbol", "date", "open", "high", "low", "close", + "volume", "amount", "raw_close", "raw_high", "raw_low"] + if c in df_latest.columns] + lf = ( + pl.scan_parquet(self._enriched_glob) + .filter(pl.col("date") >= start_full) + .sort(["symbol", "date"]) + ) + df_hist = lf.select(read_cols).collect() + if not df_hist.is_empty(): + instruments = self._instruments_cache if self._instruments_cache is not None else pl.DataFrame() + df_full = compute_indicators(df_hist) + df_full = compute_signals(df_full) + if instruments is not None and not instruments.is_empty(): + df_full = compute_limit_signals(df_full, instruments) + + # JOIN instruments 到完整历史 (filter_history/basic_filter 需要 name/股本等列) + if instruments is not None and not instruments.is_empty(): + inst_cols = [c for c in ["name", "total_shares", "float_shares"] + if c in instruments.columns and c not in df_full.columns] + if inst_cols: + df_full = df_full.join( + instruments.select(["symbol", *inst_cols]).unique(subset=["symbol"]), + on="symbol", + how="left", + ) + + # 缓存完整历史 (含指标+必要基础信息) 供 filter_history/backtest 直接复用 + self._enriched_history_cache = df_full + self._enriched_history_start = df_full["date"].min() + logger.info("enriched 历史缓存: %d rows, %s ~ %s", + len(df_full), self._enriched_history_start, latest) + + # 只取最新一天作为 enriched_cache + df_today = df_full.filter(pl.col("date") == latest) + if not df_today.is_empty(): + self._enriched_cache = df_today + self._enriched_cache_date = latest + # 构建盘中递推基准: 若最新分区是今天的实时盘中数据, + # 递推状态必须停在上一交易日, 不能把今天作为“昨日”。 + self._build_live_agg(self._live_agg_baseline_date(latest)) + logger.info("enriched 缓存已计算: %d 只, 日期 %s (即时计算)", len(df_today), latest) + return + except Exception as e: # noqa: BLE001 + logger.warning("enriched 即时计算失败, 使用原始 14 列缓存: %s", e) + + # 降级: 直接使用 14 列数据 + 构建 live_agg + self._enriched_cache = df_latest + self._enriched_cache_date = latest + self._build_live_agg(self._live_agg_baseline_date(latest)) + + logger.info("enriched 缓存已加载: %d 只, 日期 %s", len(df_latest), latest) + except Exception as e: # noqa: BLE001 + logger.warning("enriched 缓存刷新失败: %s", e) + + def _build_live_agg(self, latest: date) -> None: + """从 OHLCV 即时计算递推状态 + 窗口聚合, 构建盘中实时聚合表。 + + 优化: 优先使用 _enriched_history_cache (启动时已计算), 避免重复 compute_indicators。 + """ + from datetime import timedelta + from app.indicators.pipeline import _ema_alpha + + start_60d = latest - timedelta(days=90) # 日历90天 ≈ 60个交易日 + + # 优先使用已有的历史缓存 (避免重复 scan_parquet + compute_indicators) + if self._enriched_history_cache is not None and not self._enriched_history_cache.is_empty(): + hist_all = self._enriched_history_cache + if "date" in hist_all.columns and hist_all["date"].min() <= start_60d: + # 从历史缓存中提取所需列 (历史缓存已有指标列) + base_cols = ["symbol", "date", "open", "high", "low", "close", "volume", + "raw_close", "raw_high", "raw_low"] + needed = [c for c in base_cols if c in hist_all.columns] + df_hist = hist_all.filter( + (pl.col("date") >= start_60d) & (pl.col("date") <= latest) + ).select(needed).sort(["symbol", "date"]) + + # 用历史缓存的指标列提取最新日状态 (无需再次 compute_indicators) + state_source = hist_all.filter(pl.col("date") == latest) + + state_cols = [ + "symbol", + "ema5", "ema10", "ema20", "ema30", "ema60", + "macd_dea", + "kdj_k", "kdj_d", + "atr_14", + "close", "high", "low", + "annual_vol_20d", + ] + existing_state = [c for c in state_cols if c in state_source.columns] + agg_a = state_source.select(existing_state) + else: + df_hist = pl.DataFrame() + agg_a = pl.DataFrame() + else: + # 降级: 读 parquet + compute_indicators + df_hist, agg_a = self._build_live_agg_from_parquet(latest, start_60d) + + if df_hist.is_empty(): + self._live_agg_cache = pl.DataFrame() + self._live_agg_cache_date = None + return + + if agg_a.is_empty(): + self._live_agg_cache = pl.DataFrame() + self._live_agg_cache_date = None + return + + # 单独计算 _ema12 / _ema26 (compute_indicators 内部会 drop 掉) + df_ema = df_hist.sort(["symbol", "date"]).with_columns([ + pl.col("close").ewm_mean(alpha=_ema_alpha(12), adjust=False).over("symbol").alias("_ema12"), + pl.col("close").ewm_mean(alpha=_ema_alpha(26), adjust=False).over("symbol").alias("_ema26"), + ]).filter(pl.col("date") == latest).select("symbol", "_ema12", "_ema26") + + agg_a = agg_a.join(df_ema, on="symbol", how="inner") + + # 单独计算 RSI 状态列 (compute_indicators 内部会 drop 掉) + df_rsi_base = df_hist.sort(["symbol", "date"]).with_columns( + pl.col("close").diff().over("symbol").alias("_daily_delta") + ) + gain = pl.when(pl.col("_daily_delta") > 0).then(pl.col("_daily_delta")).otherwise(0.0) + loss = pl.when(pl.col("_daily_delta") < 0).then(-pl.col("_daily_delta")).otherwise(0.0) + rsi_exprs = [] + for n in (6, 14, 24): + a = 1.0 / n + rsi_exprs.append(gain.ewm_mean(alpha=a, adjust=False).over("symbol").alias(f"_rsi_avg_gain_{n}")) + rsi_exprs.append(loss.ewm_mean(alpha=a, adjust=False).over("symbol").alias(f"_rsi_avg_loss_{n}")) + df_rsi = ( + df_rsi_base + .with_columns(rsi_exprs) + .filter(pl.col("date") == latest) + .select("symbol", *[f"_rsi_avg_gain_{n}" for n in (6, 14, 24)], + *[f"_rsi_avg_loss_{n}" for n in (6, 14, 24)]) + ) + agg_a = agg_a.join(df_rsi, on="symbol", how="inner") + + # 前复权因子: adj_factor = close(复权) / raw_close(原始) + if "raw_close" in df_hist.columns: + adj_factor_df = ( + df_hist.filter(pl.col("date") == latest) + .select("symbol", (pl.col("close") / pl.col("raw_close")).alias("_adj_factor")) + ) + agg_a = agg_a.join(adj_factor_df, on="symbol", how="left") + if "_adj_factor" in agg_a.columns: + agg_a = agg_a.with_columns(pl.col("_adj_factor").fill_null(1.0)) + + # annual_vol_20d 递推状态: 最近 19 天日收益率的部分和 / 平方和 + df_daily_pct = ( + df_hist.sort(["symbol", "date"]) + .with_columns( + pl.col("close").pct_change().over("symbol").alias("_daily_pct") + ) + ) + df_vol = df_daily_pct.group_by("symbol").agg([ + pl.col("_daily_pct").tail(19).sum().alias("_vol_19d_pct_sum"), + (pl.col("_daily_pct") ** 2).tail(19).sum().alias("_vol_19d_pct_sq_sum"), + ]) + agg_a = agg_a.join(df_vol, on="symbol", how="left") + + # 昨日连板数: 从 enriched parquet 取 (用于增量计算同向 +1) + lf = pl.scan_parquet(self._enriched_glob).filter(pl.col("date") == latest) + consec_cols = [c for c in ["symbol", "consecutive_limit_ups", "consecutive_limit_downs"] + if c in lf.collect_schema().names()] + if len(consec_cols) == 3: + consec_df = lf.select(consec_cols).collect() + if not consec_df.is_empty(): + consec = consec_df.select( + "symbol", + pl.col("consecutive_limit_ups").alias("_prev_consec_up"), + pl.col("consecutive_limit_downs").alias("_prev_consec_down"), + ) + agg_a = agg_a.join(consec, on="symbol", how="left") + + # B类: 按 symbol 分组聚合 — 窗口统计 + agg_b = ( + df_hist.sort(["symbol", "date"]) + .group_by("symbol") + .agg([ + pl.col("close").tail(4).sum().alias("_ma5_partial_sum"), + pl.col("close").tail(9).sum().alias("_ma10_partial_sum"), + pl.col("close").tail(19).sum().alias("_ma20_partial_sum"), + pl.col("close").tail(29).sum().alias("_ma30_partial_sum"), + pl.col("close").tail(59).sum().alias("_ma60_partial_sum"), + + pl.col("close").tail(19).sum().alias("_boll_partial_sum"), + (pl.col("close").tail(19) ** 2).sum().alias("_boll_partial_sq_sum"), + + pl.col("high").tail(59).max().alias("_high_59d"), + pl.col("low").tail(59).min().alias("_low_59d"), + + pl.col("close").tail(5).first().alias("_close_5d_ago"), + pl.col("close").tail(10).first().alias("_close_10d_ago"), + pl.col("close").tail(20).first().alias("_close_20d_ago"), + pl.col("close").tail(30).first().alias("_close_30d_ago"), + pl.col("close").tail(60).first().alias("_close_60d_ago"), + + pl.col("volume").tail(4).sum().alias("_vol_ma5_partial_sum"), + pl.col("volume").tail(9).sum().alias("_vol_ma10_partial_sum"), + + pl.col("low").tail(8).min().alias("_kdj_8d_low"), + pl.col("high").tail(8).max().alias("_kdj_8d_high"), + + pl.col("close").tail(59).len().alias("_window_len"), + ]) + ) + + self._live_agg_cache = agg_a.join(agg_b, on="symbol", how="inner") + self._live_agg_cache_date = latest + + def _live_agg_baseline_date(self, latest: date) -> date: + """盘中递推基准日期。当天实时分区存在时使用上一可用交易日。""" + if latest != date.today(): + return latest + try: + row = self.execute_one( + "SELECT max(date) FROM kline_enriched WHERE date < ?", + [latest], + ) + if row and row[0]: + d = row[0] + return d if isinstance(d, date) else date.fromisoformat(str(d)) + except Exception: # noqa: BLE001 + pass + return latest + + def _build_live_agg_from_parquet(self, latest: date, start_60d: date) -> tuple[pl.DataFrame, pl.DataFrame]: + """降级路径: 从 parquet 读取数据并计算指标 (当 _enriched_history_cache 不可用时)。""" + from app.indicators.pipeline import compute_indicators + + lf = ( + pl.scan_parquet(self._enriched_glob) + .filter(pl.col("date") >= start_60d) + .filter(pl.col("date") <= latest) + .sort(["symbol", "date"]) + ) + + read_cols = [c for c in ["symbol", "date", "open", "high", "low", "close", "volume", + "raw_close", "raw_high", "raw_low"] + if c in lf.collect_schema().names()] + df_hist = lf.select(read_cols).collect() + + if df_hist.is_empty(): + return df_hist, pl.DataFrame() + + df_with_indicators = compute_indicators(df_hist) + + state_cols = [ + "symbol", + "ema5", "ema10", "ema20", "ema30", "ema60", + "macd_dea", + "kdj_k", "kdj_d", + "atr_14", + "close", "high", "low", + "annual_vol_20d", + ] + existing_state = [c for c in state_cols if c in df_with_indicators.columns] + agg_a = df_with_indicators.filter(pl.col("date") == latest).select(existing_state) + + return df_hist, agg_a + + def _refresh_instruments(self) -> None: + """加载 instruments 到内存。""" + try: + df = pl.scan_parquet(self._inst_glob).collect() + if not df.is_empty(): + self._instruments_cache = df + logger.info("instruments 缓存已加载: %d 只", len(df)) + except Exception as e: # noqa: BLE001 + logger.warning("instruments 缓存刷新失败: %s", e) + + def _refresh_index_instruments(self) -> None: + """加载指数 instruments 到内存。""" + try: + df = pl.scan_parquet(self._index_inst_glob).collect() + if not df.is_empty(): + self._index_instruments_cache = df + logger.info("index instruments 缓存已加载: %d 只", len(df)) + except Exception as e: # noqa: BLE001 + logger.debug("index instruments 缓存刷新跳过: %s", e) + + def get_enriched_latest(self) -> tuple[pl.DataFrame, date | None]: + """返回缓存的 enriched 最新日 DataFrame + 日期。如无缓存则懒加载。""" + if self._enriched_cache is None: + self._refresh_enriched() + if self._enriched_cache is None: + return pl.DataFrame(), self._enriched_cache_date + return self._enriched_cache, self._enriched_cache_date + + def get_enriched_history(self, target_date: date, lookback_days: int) -> pl.DataFrame | None: + """返回预计算的 enriched 历史数据 (仅 lookback 范围, 不含 warmup)。 + + warmup 部分在 _refresh_enriched 计算指标时已使用, 策略只需要最终的 lookback 窗口。 + 返回 ~33万行 (90日历天) 而非 ~107万行, filter_history 策略的 group_by 快 20x+。 + """ + cache = self._enriched_history_cache + if cache is None or cache.is_empty(): + return None + if "date" not in cache.columns: + return None + cache_max = cache["date"].max() + cache_min = cache["date"].min() + from datetime import timedelta + # 验证缓存覆盖完整范围 (含 warmup) + warmup_start = target_date - timedelta(days=(lookback_days + 60) * 2) + if cache_min > warmup_start or cache_max < target_date: + return None + # 只返回 lookback 范围 (日历天数 ≈ 2/3 交易日, 足够覆盖) + lookback_start = target_date - timedelta(days=lookback_days) + return cache.filter((pl.col("date") >= lookback_start) & (pl.col("date") <= target_date)) + + def get_enriched_range( + self, + start: date, + end: date, + symbols: list[str] | None = None, + columns: list[str] | None = None, + ) -> pl.DataFrame | None: + """从预计算 enriched 历史缓存返回完整区间;缓存不覆盖时返回 None。""" + if self._enriched_history_cache is None: + self._refresh_enriched() + cache = self._enriched_history_cache + if cache is None or cache.is_empty() or "date" not in cache.columns: + return None + + cache_min = cache["date"].min() + cache_max = cache["date"].max() + if cache_min > start or cache_max < end: + return None + + df = cache.filter((pl.col("date") >= start) & (pl.col("date") <= end)) + if symbols is not None: + df = df.filter(pl.col("symbol").is_in(symbols)) + if columns and not df.is_empty(): + existing = [c for c in columns if c in df.columns] + if "symbol" not in existing and "symbol" in df.columns: + existing.insert(0, "symbol") + if "date" not in existing and "date" in df.columns: + existing.insert(1, "date") + df = df.select(existing) + return df.sort(["symbol", "date"]) + + def get_live_agg(self) -> pl.DataFrame: + """返回盘中实时指标预计算聚合表。如无缓存则懒加载。""" + if self._live_agg_cache is None: + self._refresh_enriched() + if self._live_agg_cache is None: + return pl.DataFrame() + return self._live_agg_cache + + def get_instruments(self) -> pl.DataFrame: + """返回缓存的 instruments DataFrame。如无缓存则懒加载。""" + if self._instruments_cache is None: + self._refresh_instruments() + if self._instruments_cache is None: + return pl.DataFrame() + return self._instruments_cache + + def get_index_instruments(self) -> pl.DataFrame: + """返回缓存的指数 instruments DataFrame。如无缓存则懒加载。""" + if self._index_instruments_cache is None: + self._refresh_index_instruments() + if self._index_instruments_cache is None: + return pl.DataFrame() + return self._index_instruments_cache + + def get_index_symbol_set(self) -> set[str]: + """返回已缓存指数 symbol 集合。""" + df = self.get_index_instruments() + if df.is_empty() or "symbol" not in df.columns: + return set() + return set(df["symbol"].cast(pl.Utf8).to_list()) + + def enriched_latest_date(self) -> date | None: + """返回缓存中的 enriched 最新日期。""" + return self._enriched_cache_date + + # ================================================================ + # 热路径: Polars 查询 (Chart / Screener / Signals / Intraday) + # ================================================================ + + def get_daily( + self, + symbol: str, + start: date, + end: date, + columns: list[str] | None = None, + ) -> pl.DataFrame: + """单股日K查询 — 从14列parquet读取后即时计算指标。""" + from datetime import timedelta + + # 扩展范围用于指标预热 (MA60 需要 ~60 交易日 ≈ 120 日历日) + warmup_start = start - timedelta(days=150) + + # 扫描14列 parquet + df = self._scan_daily_symbol(symbol, warmup_start, end, None) + if not df.is_empty(): + df = self._compute_enriched_range(df) + + # 尝试用缓存数据覆盖最新日 (盘中更准确) + cached, cache_date = self.get_enriched_latest() + if not df.is_empty() and cached is not None and not cached.is_empty() and cache_date: + if start <= cache_date <= end: + cached_part = self._filter_cached(cached, symbol, None) + if not cached_part.is_empty(): + df = df.filter(pl.col("date") != cache_date) + common_cols = [c for c in df.columns if c in cached_part.columns] + df = pl.concat([df.select(common_cols), cached_part.select(common_cols)]) + + # 裁剪到请求范围 + if not df.is_empty(): + df = df.filter((pl.col("date") >= start) & (pl.col("date") <= end)) + + if columns and not df.is_empty(): + existing = [c for c in columns if c in df.columns] + df = df.select(existing) + + return df + + def get_daily_batch( + self, + symbols: list[str], + start: date, + end: date, + columns: list[str] | None = None, + ) -> pl.DataFrame: + """批量日K查询。""" + cached, cache_date = self.get_enriched_latest() + if cached is not None and not cached.is_empty() and cache_date: + if start >= cache_date: + return self._filter_cached_batch(cached, symbols, columns) + + # 回退 scan_parquet + return self._scan_daily_batch(symbols, start, end, columns) + + def get_index_daily( + self, + symbol: str, + start: date, + end: date, + columns: list[str] | None = None, + ) -> pl.DataFrame: + """指数日K查询 — 从独立指数 enriched parquet 读取后即时计算通用指标。""" + from datetime import timedelta + + warmup_start = start - timedelta(days=150) + df = self._scan_index_daily_symbol(symbol, warmup_start, end, None) + if not df.is_empty(): + df = self._compute_index_enriched_range(df) + df = df.filter((pl.col("date") >= start) & (pl.col("date") <= end)) + if columns and not df.is_empty(): + existing = [c for c in columns if c in df.columns] + df = df.select(existing) + return df + + def get_minute( + self, + symbol: str, + trade_date: date, + ) -> pl.DataFrame: + """分钟K查询 — Polars scan_parquet + predicate pushdown。""" + try: + return pl.scan_parquet(self._minute_glob).filter( + (pl.col("symbol") == symbol) + & (pl.col("datetime").dt.date() == trade_date) + ).sort("datetime").collect() + except Exception as e: # noqa: BLE001 + logger.warning("分钟K查询失败: %s", e) + return pl.DataFrame() + + # ================================================================ + # Polars 查询内部方法 + # ================================================================ + + def _compute_enriched_range(self, df: pl.DataFrame) -> pl.DataFrame: + """对14列enriched数据即时计算完整指标+信号。输入应含足够预热行数。""" + from app.indicators.pipeline import compute_indicators, compute_signals, compute_limit_signals, filter_halt_days + if df.is_empty() or df.height < 2: + return df + # 兜底过滤历史脏数据中的停牌日 (close 可能被填充为前收盘价) + df = filter_halt_days(df) + if df.is_empty() or df.height < 2: + return df + try: + df = compute_indicators(df) + df = compute_signals(df) + instruments = self.get_instruments() + df = compute_limit_signals(df, instruments) + except Exception as e: # noqa: BLE001 + logger.warning("on-demand compute failed: %s", e) + return df + + def _compute_index_enriched_range(self, df: pl.DataFrame) -> pl.DataFrame: + """指数只计算通用技术指标和通用信号,跳过涨跌停/股本/市值逻辑。""" + from app.indicators.pipeline import compute_indicators, compute_signals + if df.is_empty() or df.height < 2: + return df + try: + df = compute_indicators(df) + df = compute_signals(df) + except Exception as e: # noqa: BLE001 + logger.warning("index on-demand compute failed: %s", e) + return df + + def _filter_cached(self, cached: pl.DataFrame, symbol: str, columns: list[str] | None) -> pl.DataFrame: + df = cached.filter(pl.col("symbol") == symbol) + if columns and not df.is_empty(): + existing = [c for c in columns if c in df.columns] + df = df.select(existing) + return df + + def _filter_cached_batch(self, cached: pl.DataFrame, symbols: list[str], columns: list[str] | None) -> pl.DataFrame: + df = cached.filter(pl.col("symbol").is_in(symbols)) + if columns and not df.is_empty(): + existing = [c for c in columns if c in df.columns] + df = df.select(existing) + return df.sort(["symbol", "date"]) + + def _scan_daily_symbol(self, symbol: str, start: date, end: date, columns: list[str] | None) -> pl.DataFrame: + try: + lf = pl.scan_parquet(self._enriched_glob, + cast_options=pl.ScanCastOptions(integer_cast="allow-float")).filter( + (pl.col("symbol") == symbol) + & (pl.col("date") >= start) + & (pl.col("date") <= end) + ).sort("date") + if columns: + schema_names = lf.collect_schema().names() + existing = [c for c in columns if c in schema_names] + lf = lf.select(existing) + return lf.collect() + except Exception as e: # noqa: BLE001 + logger.warning("日K查询失败: %s", e) + return pl.DataFrame() + + def _scan_daily_batch(self, symbols: list[str], start: date, end: date, columns: list[str] | None) -> pl.DataFrame: + try: + lf = pl.scan_parquet(self._enriched_glob, + cast_options=pl.ScanCastOptions(integer_cast="allow-float")).filter( + (pl.col("symbol").is_in(symbols)) + & (pl.col("date") >= start) + & (pl.col("date") <= end) + ).sort(["symbol", "date"]) + if columns: + schema_names = lf.collect_schema().names() + existing = [c for c in columns if c in schema_names] + lf = lf.select(existing) + return lf.collect() + except Exception as e: # noqa: BLE001 + logger.warning("日K批量查询失败: %s", e) + return pl.DataFrame() + + def _scan_index_daily_symbol(self, symbol: str, start: date, end: date, columns: list[str] | None) -> pl.DataFrame: + try: + lf = pl.scan_parquet(self._index_enriched_glob, + cast_options=pl.ScanCastOptions(integer_cast="allow-float")).filter( + (pl.col("symbol") == symbol) + & (pl.col("date") >= start) + & (pl.col("date") <= end) + ).sort("date") + if columns: + schema_names = lf.collect_schema().names() + existing = [c for c in columns if c in schema_names] + lf = lf.select(existing) + return lf.collect() + except Exception as e: # noqa: BLE001 + logger.warning("指数日K查询失败: %s", e) + return pl.DataFrame() + + def _merge_cached_and_scan( + self, + cached: pl.DataFrame, + cache_date: date, + symbol: str, + start: date, + end: date, + columns: list[str] | None, + ) -> pl.DataFrame: + """合并缓存部分 + scan 历史部分。 + + 历史部分用 strict < cache_date, 避免与缓存重复。 + 两部分 schema 可能不一致 (增量 vs 全量), concat 前对齐列。 + """ + hist = self._scan_daily_symbol(symbol, start, cache_date, columns) + cached_part = self._filter_cached(cached, symbol, columns) + if hist.is_empty(): + return cached_part + if cached_part.is_empty(): + return hist + # 去重: 历史部分可能包含 cache_date, 去掉后再合并 + hist = hist.filter(pl.col("date") < cache_date) + # 对齐列: 取交集, 统一类型 + common_cols = [c for c in hist.columns if c in cached_part.columns] + hist = hist.select(common_cols) + cached_part = cached_part.select(common_cols) + # 统一类型: 历史可能是 Float64, 缓存可能是 Int64, 统一为 cast + for c in common_cols: + if hist[c].dtype != cached_part[c].dtype: + # 统一到更宽的类型 + target = hist[c].dtype if hist.height > cached_part.height else cached_part[c].dtype + hist = hist.with_columns(pl.col(c).cast(target)) + cached_part = cached_part.with_columns(pl.col(c).cast(target)) + return pl.concat([hist, cached_part]) + + # ================================================================ + # DuckDB 查询 (冷路径: 统计/元数据/自定义SQL) + # ================================================================ + + def latest_minute_date(self, symbol: str) -> date | None: + try: + with self._lock: + row = self.db.execute( + "SELECT max(CAST(datetime AS DATE)) FROM kline_minute WHERE symbol = ?", + [symbol], + ).fetchone() + if row and row[0]: + return row[0] if isinstance(row[0], date) else date.fromisoformat(str(row[0])) + except duckdb.CatalogException: + pass + return None + + def earliest_daily_date(self) -> date | None: + """本地日K数据的最早日期。""" + try: + with self._lock: + res = self.db.execute( + "SELECT min(date) FROM kline_daily", + ).fetchone() + if res and res[0]: + d = res[0] + return d if isinstance(d, date) else date.fromisoformat(str(d)) + except Exception: + return None + return None + + def earliest_minute_date(self) -> date | None: + """本地分钟K数据的最早日期。""" + try: + with self._lock: + res = self.db.execute( + "SELECT min(CAST(datetime AS DATE)) FROM kline_minute", + ).fetchone() + if res and res[0]: + d = res[0] + return d if isinstance(d, date) else date.fromisoformat(str(d)) + except Exception: + return None + return None + + def latest_daily_date(self) -> date | None: + """本地日K数据的最新日期。""" + try: + with self._lock: + res = self.db.execute( + "SELECT max(date) FROM kline_daily", + ).fetchone() + if res and res[0]: + d = res[0] + return d if isinstance(d, date) else date.fromisoformat(str(d)) + except Exception: + return None + return None + + def _latest_enriched_date_duckdb(self) -> date | None: + try: + with self._lock: + res = self.db.execute( + "SELECT max(date) FROM kline_enriched", + ).fetchone() + if res and res[0]: + d = res[0] + return d if isinstance(d, date) else date.fromisoformat(str(d)) + except Exception: # noqa: BLE001 + return None + return None + + # ================================================================ + # 写入 (Pipeline / Sync) + # ================================================================ + + def append_daily(self, df: pl.DataFrame) -> None: + """按日分区写入日K数据 (merge-upsert)。""" + if df.is_empty(): + return + self._write_daily_partition(df, "kline_daily") + + def append_enriched(self, df: pl.DataFrame) -> None: + """按日分区写入 enriched 数据 (merge-upsert)。磁盘仅写入 14 列存储列。""" + if df.is_empty(): + return + from app.indicators.pipeline import ENRICHED_STORAGE_COLS + storage_cols = [c for c in ENRICHED_STORAGE_COLS if c in df.columns] + df_storage = df.select(storage_cols) + self._write_daily_partition(df_storage, "kline_daily_enriched") + + def append_index_daily(self, df: pl.DataFrame) -> None: + """按日分区写入指数日K数据 (merge-upsert)。""" + if df.is_empty(): + return + self._write_daily_partition(df, "kline_index_daily") + + def append_index_enriched(self, df: pl.DataFrame) -> None: + """按日分区写入指数 enriched 数据。磁盘仅写入通用基础行情窄表。""" + if df.is_empty(): + return + from app.indicators.pipeline import ENRICHED_STORAGE_COLS + storage_cols = [c for c in ENRICHED_STORAGE_COLS if c in df.columns] + df_storage = df.select(storage_cols) + self._write_daily_partition(df_storage, "kline_index_enriched") + + def save_index_instruments(self, df: pl.DataFrame) -> None: + """保存指数标的维表。""" + if df.is_empty() or "symbol" not in df.columns: + return + out = self.store.data_dir / "instruments_index" / "instruments_index.parquet" + out.parent.mkdir(parents=True, exist_ok=True) + df.unique(subset=["symbol"], keep="last").sort("symbol").write_parquet(out) + self._index_instruments_cache = None + self._refresh_index_instruments() + + def refresh_index_views(self) -> None: + """刷新指数相关 DuckDB 视图。""" + d = self.store.data_dir.as_posix() + statements = [ + f"""CREATE OR REPLACE VIEW kline_index_daily AS + SELECT * FROM read_parquet('{d}/kline_index_daily/**/*.parquet', union_by_name=true)""", + f"""CREATE OR REPLACE VIEW kline_index_enriched AS + SELECT * FROM read_parquet('{d}/kline_index_enriched/**/*.parquet', union_by_name=true)""", + f"""CREATE OR REPLACE VIEW instruments_index AS + SELECT * FROM read_parquet('{d}/instruments_index/**/*.parquet', union_by_name=true)""", + ] + for sql in statements: + try: + with self._lock: + self.db.execute(sql) + except Exception as e: # noqa: BLE001 + logger.debug("index view refresh skipped: %s", e) + + def _write_daily_partition(self, df: pl.DataFrame, table: str) -> None: + """按 date 分区写入 parquet,每个日期一个文件,支持 merge-upsert。""" + base = self.store.data_dir / table + for date_df in df.partition_by("date"): + dt = date_df["date"][0] + ds = dt.isoformat() if hasattr(dt, "isoformat") else str(dt) + out = base / f"date={ds}" / "part.parquet" + out.parent.mkdir(parents=True, exist_ok=True) + if out.exists(): + existing = pl.read_parquet(out) + date_df = pl.concat([existing, date_df], how="diagonal_relaxed").unique( + subset=["symbol", "date"], keep="last" + ) + date_df = date_df.sort(["symbol", "date"]) + date_df.write_parquet(out) + + def flush_live_daily(self, df: pl.DataFrame) -> None: + """覆写当天 kline_daily 分区 (实时行情落盘, 非merge)。""" + if df.is_empty() or "date" not in df.columns: + return + base = self.store.data_dir / "kline_daily" + dt = df["date"][0] + ds = dt.isoformat() if hasattr(dt, "isoformat") else str(dt) + out = base / f"date={ds}" / "part.parquet" + out.parent.mkdir(parents=True, exist_ok=True) + df.sort(["symbol", "date"]).write_parquet(out) + + def flush_live_enriched(self, df: pl.DataFrame) -> None: + """覆写当天 kline_daily_enriched 分区 (实时 enriched 落盘, 非merge)。 + + 内存缓存保留完整指标列供各服务使用,磁盘仅写入 14 列存储列。 + """ + if df.is_empty() or "date" not in df.columns: + return + # 内存缓存: 保留完整 66 列 + self._enriched_cache = df.sort(["symbol"]) + dt = df["date"][0] + self._enriched_cache_date = dt + # 磁盘写入: 仅 14 列存储列 + from app.indicators.pipeline import ENRICHED_STORAGE_COLS + storage_cols = [c for c in ENRICHED_STORAGE_COLS if c in df.columns] + df_storage = df.select(storage_cols).sort(["symbol"]) + base = self.store.data_dir / "kline_daily_enriched" + ds = dt.isoformat() if hasattr(dt, "isoformat") else str(dt) + out = base / f"date={ds}" / "part.parquet" + out.parent.mkdir(parents=True, exist_ok=True) + df_storage.write_parquet(out) diff --git a/backend/app/tickflow/scheduler.py b/backend/app/tickflow/scheduler.py new file mode 100644 index 0000000..588b67c --- /dev/null +++ b/backend/app/tickflow/scheduler.py @@ -0,0 +1,66 @@ +"""请求调度器(§5.6)。 + +按 capability 分别维护令牌桶。Phase 0:基础实现;Phase 1 接入批量合并、优先级队列。 +""" +from __future__ import annotations + +import asyncio +import time +from dataclasses import dataclass + +from .capabilities import Cap, CapabilitySet + + +@dataclass +class _Bucket: + capacity: int # 每分钟令牌数 + tokens: float + last_refill: float # 单位:秒 + + def consume(self, n: int = 1) -> float: + """尝试消费 n 个令牌,返回需要等待的秒数(0 表示无需等待)。""" + now = time.monotonic() + elapsed = now - self.last_refill + # 60s 内补满 capacity,匀速补 + refill = elapsed * (self.capacity / 60.0) + self.tokens = min(self.capacity, self.tokens + refill) + self.last_refill = now + + if self.tokens >= n: + self.tokens -= n + return 0.0 + deficit = n - self.tokens + # 还需多少秒才能补齐 + wait = deficit / (self.capacity / 60.0) + # 不预扣,留给下一次再竞争(避免饿死优先级高的请求) + return wait + + +class Scheduler: + """每个 capability 一个桶。""" + + def __init__(self, capset: CapabilitySet) -> None: + self._capset = capset + self._buckets: dict[Cap, _Bucket] = {} + self._locks: dict[Cap, asyncio.Lock] = {} + for cap, lim in capset.all().items(): + if lim.rpm: + self._buckets[cap] = _Bucket( + capacity=lim.rpm, + tokens=lim.rpm, + last_refill=time.monotonic(), + ) + self._locks[cap] = asyncio.Lock() + + async def acquire(self, cap: Cap, n: int = 1) -> None: + """阻塞直到拿到 n 个令牌。无桶 = 不限流(由调用方保证)。""" + bucket = self._buckets.get(cap) + if bucket is None: + return + lock = self._locks[cap] + async with lock: + while True: + wait = bucket.consume(n) + if wait == 0: + return + await asyncio.sleep(wait) diff --git a/backend/pyproject.toml b/backend/pyproject.toml new file mode 100644 index 0000000..068f4b2 --- /dev/null +++ b/backend/pyproject.toml @@ -0,0 +1,65 @@ +[project] +name = "tf-stocks-panel-backend" +version = "0.1.0" +description = "A 股选股 + 监控 + 回测面板 — TickFlow 适配" +readme = "../README.md" +requires-python = ">=3.11" +license = { text = "MIT" } +dependencies = [ + # Web + "fastapi>=0.115", + "uvicorn[standard]>=0.30", + "pydantic>=2.7", + "pydantic-settings>=2.4", + "python-multipart>=0.0.6", + "sse-starlette>=2.0", + # Data + "polars>=1.0", + "duckdb>=1.0", + "pyarrow>=16.0", + "pandas>=2.2", # 仅在 BacktestService 边界使用,见 §7.4 / ADR-19 + "fastexcel>=0.10", # Polars 读取 xlsx/xls + # TickFlow 官方 SDK + "tickflow[all]>=0.1.21", + # Scheduling + "apscheduler>=3.10", + # Config + "pyyaml>=6.0", + "python-dotenv>=1.0", + # AI(可选,但默认装上) + "openai>=1.40", # OpenAI 兼容适配器复用 openai SDK + "httpx>=0.27", +] + +[project.optional-dependencies] +# 回测依赖 vectorbt → numba → llvmlite,体积大且 macOS/Intel 上无预构建 wheel 时 +# 需要 brew install cmake 现场编译。挪到可选 extras,主依赖瘦身。 +# 启用:`uv sync --extra backtest` +backtest = [ + "vectorbt>=0.26", +] + +dev = [ + "pytest>=8.0", + "pytest-asyncio>=0.23", + "ruff>=0.5", + "mypy>=1.10", +] + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +packages = ["app"] + +[tool.ruff] +line-length = 100 +target-version = "py311" + +[tool.ruff.lint] +select = ["E", "F", "I", "N", "UP", "B", "SIM", "RUF"] +ignore = ["E501"] # 长行交给 fmt + +[tool.pytest.ini_options] +asyncio_mode = "auto" diff --git a/backend/scripts/__init__.py b/backend/scripts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/scripts/cleanup_halt_days.py b/backend/scripts/cleanup_halt_days.py new file mode 100644 index 0000000..43174f8 --- /dev/null +++ b/backend/scripts/cleanup_halt_days.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python +"""一次性清理脚本:移除已入库的停牌脏数据。 + +背景:历史停牌过滤条件为 "OHLC 全零",会漏过 close 被数据源填充为 +前收盘价的停牌记录(如 *ST 撤销风险警示的停牌日),导致日 K 图出现 +开盘价为 0 的异常蜡烛。停牌过滤已改用 "open==0 且 high==0",本脚本 +负责清理既有脏数据,可重复执行(幂等)。 + +用法(从 backend/ 目录运行): + .venv/bin/python -m scripts.cleanup_halt_days # 清理 + dry-run 关闭 + .venv/bin/python -m scripts.cleanup_halt_days --dry-run # 仅扫描,不写盘 +""" +from __future__ import annotations + +import argparse +import logging +from pathlib import Path + +import polars as pl + +logger = logging.getLogger(__name__) + +# kline_daily 原始表与 enriched 表的脏数据都在这些分区里 +HALT_TABLES = ["kline_daily", "kline_daily_enriched"] +DATA_DIR = Path(__file__).resolve().parent.parent.parent / "data" +HALT_PRED = (pl.col("open") == 0) & (pl.col("high") == 0) + + +def _scan_dirty(table: str) -> pl.DataFrame: + glob = str(DATA_DIR / table / "**" / "*.parquet") + cast = pl.ScanCastOptions(integer_cast="allow-float") + return ( + pl.scan_parquet(glob, hive_partitioning=True, cast_options=cast) + .filter(HALT_PRED) + .select("symbol", "date") + .collect() + ) + + +def _clean_table(table: str, dry_run: bool) -> int: + """清理单张表所有脏分区,返回被删除的行数。""" + dirty = _scan_dirty(table) + if dirty.is_empty(): + logger.info("[%s] 无脏数据", table) + return 0 + + removed = 0 + base = DATA_DIR / table + for dt in dirty["date"].unique().sort(): + part = base / f"date={dt}" / "part.parquet" + if not part.exists(): + logger.warning("[%s] 分区文件不存在: %s", table, part) + continue + df = pl.read_parquet(part) + before = df.height + cleaned = df.filter(~HALT_PRED) + after = cleaned.height + diff = before - after + if diff == 0: + continue + removed += diff + if dry_run: + logger.info("[%s %s] 将删除 %d 行 (停牌), 剩余 %d 行 [dry-run]", + table, dt, diff, after) + continue + if after == 0: + part.unlink() + logger.info("[%s %s] 删除 %d 行后分区为空, 已移除文件", table, dt, diff) + else: + cleaned.write_parquet(part) + logger.info("[%s %s] 删除 %d 行 (停牌), 剩余 %d 行已重写", + table, dt, diff, after) + return removed + + +def main() -> None: + ap = argparse.ArgumentParser(description="清理已入库的停牌脏数据") + ap.add_argument("--dry-run", action="store_true", help="仅扫描不写盘") + args = ap.parse_args() + + logging.basicConfig( + level=logging.INFO, + format="%(asctime)s %(levelname)s %(message)s", + datefmt="%H:%M:%S", + ) + + total = 0 + for table in HALT_TABLES: + total += _clean_table(table, args.dry_run) + + mode = "dry-run 扫描" if args.dry_run else "已清理" + logger.info("完成: 共 %s %d 行停牌脏数据", mode, total) + + +if __name__ == "__main__": + main() diff --git a/backend/tests/backtest/test_engine_portfolio.py b/backend/tests/backtest/test_engine_portfolio.py new file mode 100644 index 0000000..8a36cb6 --- /dev/null +++ b/backend/tests/backtest/test_engine_portfolio.py @@ -0,0 +1,312 @@ +from __future__ import annotations + +from datetime import date, timedelta + +import polars as pl + +from app.backtest.engine import BacktestEngine, MatcherConfig + + +def _panel(symbols: list[str], days: int = 4, price: float = 10.0, overrides: dict[tuple[str, int], dict] | None = None) -> pl.DataFrame: + overrides = overrides or {} + start = date(2024, 1, 1) + rows = [] + for sym in symbols: + for i in range(days): + patch = overrides.get((sym, i), {}) + rows.append({ + "symbol": sym, + "name": sym, + "date": start + timedelta(days=i), + "open": patch.get("open", price), + "high": patch.get("high", price), + "low": patch.get("low", price), + "close": patch.get("close", price), + "volume": patch.get("volume", 100_000), + "score": patch.get("score", {"A": 4, "B": 3, "C": 2, "D": 1}.get(sym, 0)), + "signal_limit_up": patch.get("signal_limit_up", False), + "signal_limit_down": patch.get("signal_limit_down", False), + }) + return pl.DataFrame(rows).sort(["symbol", "date"]) + + +def _mask(panel: pl.DataFrame, marks: set[tuple[str, int]]) -> pl.Series: + values = [] + base = date(2024, 1, 1) + for row in panel.select(["symbol", "date"]).iter_rows(named=True): + day = (row["date"] - base).days + values.append((row["symbol"], day) in marks) + return pl.Series(values, dtype=pl.Boolean) + + +def _engine() -> BacktestEngine: + return BacktestEngine(repo=None) # simulate_portfolio 不访问 repo + + +def test_max_exposure_sets_target_position_and_caps_count(): + panel = _panel(["A", "B", "C", "D"], days=3) + entries = _mask(panel, {("A", 0), ("B", 0), ("C", 0), ("D", 0)}) + exits = _mask(panel, set()) + + result = _engine().simulate_portfolio( + panel, + entries, + exits, + MatcherConfig( + matching="open_t+1", + fees_pct=0, + slippage_bps=0, + max_positions=3, + max_exposure_pct=0.6, + initial_capital=100_000, + ), + ) + + assert len(result.trades) == 3 + assert {t.symbol for t in result.trades} == {"A", "B", "C"} + assert all(abs(t.position_pct - 0.2) < 0.001 for t in result.trades) + assert result.stats["max_exposure"] <= 0.61 + + +def test_one_price_limit_up_blocks_buy(): + panel = _panel( + ["A"], + days=3, + overrides={ + ("A", 1): {"open": 11, "high": 11, "low": 11, "close": 11, "signal_limit_up": True}, + }, + ) + entries = _mask(panel, {("A", 0)}) + exits = _mask(panel, set()) + + result = _engine().simulate_portfolio( + panel, + entries, + exits, + MatcherConfig(matching="open_t+1", fees_pct=0, slippage_bps=0, max_positions=1, initial_capital=100_000), + ) + + assert result.trades == [] + assert result.stats["execution"]["buy_limit_up"] == 1 + + +def test_failed_open_exit_keeps_slot_and_blocks_replacement_buy(): + panel = _panel( + ["A", "B", "C", "D"], + days=4, + overrides={ + ("A", 2): {"open": 9, "high": 9, "low": 9, "close": 9, "signal_limit_down": True}, + }, + ) + entries = _mask(panel, { + ("A", 0), ("B", 0), ("C", 0), + ("D", 1), + }) + exits = _mask(panel, {("A", 1)}) + + result = _engine().simulate_portfolio( + panel, + entries, + exits, + MatcherConfig( + matching="open_t+1", + fees_pct=0, + slippage_bps=0, + max_positions=3, + max_exposure_pct=0.6, + initial_capital=100_000, + ), + ) + + assert "D" not in {t.symbol for t in result.trades} + assert result.stats["execution"]["sell_limit_down"] == 1 + assert result.stats["execution"]["pending_exit"] == 1 + assert result.stats["execution"]["buy_no_slot"] >= 1 + a_trade = next(t for t in result.trades if t.symbol == "A") + assert a_trade.blocked_exit_days == 1 + assert a_trade.exit_reason == "signal" + + +def test_trailing_stop_uses_high_water_mark(): + panel = _panel( + ["A"], + days=5, + overrides={ + ("A", 2): {"open": 10, "high": 12, "low": 11.8, "close": 12}, + ("A", 3): {"open": 12, "high": 12, "low": 11.3, "close": 11.3}, + }, + ) + entries = _mask(panel, {("A", 0)}) + exits = _mask(panel, set()) + + result = _engine().simulate_portfolio( + panel, + entries, + exits, + MatcherConfig( + matching="open_t+1", + fees_pct=0, + slippage_bps=0, + max_positions=1, + initial_capital=100_000, + trailing_stop_pct=0.05, + ), + ) + + assert len(result.trades) == 1 + trade = result.trades[0] + assert trade.exit_reason == "trailing_stop" + assert trade.exit_price == 11.4 + + +def test_trailing_take_profit_requires_activation(): + panel = _panel( + ["A"], + days=5, + overrides={ + ("A", 2): {"open": 10, "high": 10.8, "low": 10.4, "close": 10.8}, + ("A", 3): {"open": 10.8, "high": 10.8, "low": 10.4, "close": 10.4}, + }, + ) + entries = _mask(panel, {("A", 0)}) + exits = _mask(panel, set()) + + result = _engine().simulate_portfolio( + panel, + entries, + exits, + MatcherConfig( + matching="open_t+1", + fees_pct=0, + slippage_bps=0, + max_positions=1, + initial_capital=100_000, + trailing_take_profit_activate_pct=0.10, + trailing_take_profit_drawdown_pct=0.03, + ), + ) + + assert result.trades[0].exit_reason == "end" + + +def test_trailing_take_profit_exits_after_activation(): + panel = _panel( + ["A"], + days=5, + overrides={ + ("A", 2): {"open": 10, "high": 12, "low": 11.8, "close": 12}, + ("A", 3): {"open": 12, "high": 12, "low": 11.5, "close": 11.5}, + }, + ) + entries = _mask(panel, {("A", 0)}) + exits = _mask(panel, set()) + + result = _engine().simulate_portfolio( + panel, + entries, + exits, + MatcherConfig( + matching="open_t+1", + fees_pct=0, + slippage_bps=0, + max_positions=1, + initial_capital=100_000, + trailing_take_profit_activate_pct=0.10, + trailing_take_profit_drawdown_pct=0.03, + ), + ) + + assert len(result.trades) == 1 + trade = result.trades[0] + assert trade.exit_reason == "trailing_take_profit" + assert trade.exit_price == 11.7 + + +def test_score_filter_uses_signal_day_score_range(): + panel = _panel( + ["A", "B", "C"], + days=3, + overrides={ + ("A", 0): {"score": 70}, + ("B", 0): {"score": 80}, + ("C", 0): {"score": 90}, + ("A", 1): {"score": 100}, + ("B", 1): {"score": 1}, + ("C", 1): {"score": 1}, + }, + ) + entries = _mask(panel, {("A", 0), ("B", 0), ("C", 0)}) + exits = _mask(panel, set()) + + result = _engine().simulate_portfolio( + panel, + entries, + exits, + MatcherConfig( + matching="open_t+1", + fees_pct=0, + slippage_bps=0, + max_positions=3, + initial_capital=100_000, + score_min=71, + score_max=85, + ), + ) + + assert {t.symbol for t in result.trades} == {"B"} + assert result.trades[0].entry_score == 80 + assert result.stats["execution"]["buy_score_filter"] == 2 + + +def test_independent_candidates_allow_overlapping_same_symbol_trades(): + panel = _panel( + ["A"], + days=5, + overrides={ + ("A", 0): {"close": 10}, + ("A", 1): {"close": 11}, + ("A", 2): {"close": 12}, + ("A", 3): {"close": 13}, + ("A", 4): {"close": 14}, + }, + ) + entries = _mask(panel, {("A", 0), ("A", 1)}) + exits = _mask(panel, set()) + + result = _engine().simulate_independent_candidates( + panel, + entries, + exits, + MatcherConfig(matching="close_t", fees_pct=0, slippage_bps=0, max_hold_days=2), + ) + + assert result.stats["full_kind"] == "candidate_execution" + assert result.stats["n_candidates"] == 2 + assert len(result.trades) == 2 + assert [t.entry_date for t in result.trades] == ["2024-01-01", "2024-01-02"] + assert [t.exit_date for t in result.trades] == ["2024-01-03", "2024-01-04"] + assert all(t.exit_reason == "max_hold" for t in result.trades) + + +def test_independent_candidates_apply_stop_loss(): + panel = _panel( + ["A"], + days=4, + overrides={ + ("A", 0): {"close": 10, "low": 10}, + ("A", 1): {"open": 10, "high": 10, "low": 8.9, "close": 9}, + }, + ) + entries = _mask(panel, {("A", 0)}) + exits = _mask(panel, set()) + + result = _engine().simulate_independent_candidates( + panel, + entries, + exits, + MatcherConfig(matching="close_t", fees_pct=0, slippage_bps=0, stop_loss_pct=0.1), + ) + + assert len(result.trades) == 1 + assert result.trades[0].exit_reason == "stop_loss" + assert result.trades[0].exit_price == 9.0 diff --git a/backend/tests/backtest/test_full_simulation_tail.py b/backend/tests/backtest/test_full_simulation_tail.py new file mode 100644 index 0000000..f5352b9 --- /dev/null +++ b/backend/tests/backtest/test_full_simulation_tail.py @@ -0,0 +1,59 @@ +"""全量模拟 (full mode) 尾部执行回归测试。""" +from __future__ import annotations + +from datetime import date, timedelta + +import polars as pl + +from app.backtest.engine import BacktestEngine, MatcherConfig + + +def _panel_with_tail(symbols: list[str], n_data_days: int) -> pl.DataFrame: + start = date(2024, 1, 1) + rows = [] + for sym in symbols: + for i in range(n_data_days): + px = 10.0 + i + rows.append({ + "symbol": sym, + "date": start + timedelta(days=i), + "open": px, + "high": px, + "low": px, + "close": px, + "volume": 100_000, + "signal_limit_up": False, + "signal_limit_down": False, + }) + return pl.DataFrame(rows).sort(["symbol", "date"]) + + +def test_full_simulation_executes_signal_at_tail(): + """信号集中在正式区间最后一天时, tail 数据应允许次日开盘买入并按策略退出。""" + n_days = 6 + panel = _panel_with_tail(["A"], n_days + 3) + + start = date(2024, 1, 1) + end = start + timedelta(days=n_days - 1) + entry_vals = [] + for row in panel.select(["symbol", "date"]).iter_rows(named=True): + entry_vals.append(row["date"] == end) + entry_mask = pl.Series(entry_vals, dtype=pl.Boolean) + exit_mask = pl.Series([False] * len(panel), dtype=pl.Boolean) + + result = BacktestEngine(repo=None).simulate_independent_candidates( # type: ignore[arg-type] + panel, + entry_mask, + exit_mask, + MatcherConfig(matching="open_t+1", fees_pct=0, slippage_bps=0, max_hold_days=2), + ) + + assert not result.stats.get("error"), f"unexpected error: {result.stats.get('error')}" + assert result.stats.get("full_kind") == "candidate_execution" + assert result.stats.get("n_candidates") == 1 + assert result.stats.get("n_trades") == 1 + assert len(result.trades) == 1 + trade = result.trades[0] + assert trade.entry_signal_date == str(end) + assert trade.entry_date == str(end + timedelta(days=1)) + assert trade.exit_reason == "max_hold" diff --git a/backend/tests/backtest/test_strategy_backtest_correctness.py b/backend/tests/backtest/test_strategy_backtest_correctness.py new file mode 100644 index 0000000..6b55ba8 --- /dev/null +++ b/backend/tests/backtest/test_strategy_backtest_correctness.py @@ -0,0 +1,163 @@ +from __future__ import annotations + +from datetime import date, timedelta +from types import SimpleNamespace + +import polars as pl + +from app.backtest.engine import BacktestEngine, SimResult +from app.backtest.strategy import StrategyBacktestConfig, StrategyBacktestService +from app.strategy.engine import StrategyDef + + +def _strategy(**kwargs) -> StrategyDef: + defaults = dict( + meta={"id": "test", "name": "test", "scoring": {}, "params": [], "limit": 100}, + basic_filter={"enabled": True, "amount_min": 100.0}, + entry_signals=[], + exit_signals=[], + stop_loss=None, + trailing_stop=None, + trailing_take_profit_activate=None, + trailing_take_profit_drawdown=None, + max_hold_days=None, + alerts=[], + filter_fn=lambda df, params: pl.lit(True), + filter_history_fn=None, + lookback_days=1, + source="custom", + file_path=None, + ) + defaults.update(kwargs) + return StrategyDef(**defaults) + + +class _StrategyEngineStub: + def __init__(self, strategy: StrategyDef) -> None: + self.strategy = strategy + + def get(self, strategy_id: str) -> StrategyDef: + return self.strategy + + +class _RepoStub: + def get_index_daily(self, *args, **kwargs) -> pl.DataFrame: + return pl.DataFrame() + + +class _EngineStub: + def __init__(self, panel: pl.DataFrame) -> None: + self.panel = panel + self.repo = _RepoStub() + self.load_args = None + self.sim_panel: pl.DataFrame | None = None + self.sim_entries: pl.Series | None = None + + def load_panel(self, symbols, start: date, end: date) -> pl.DataFrame: + self.load_args = (symbols, start, end) + return self.panel + + def simulate_portfolio(self, panel, entries, exits, config, progress_cb=None, cancel_event=None) -> SimResult: + self.sim_panel = panel + self.sim_entries = entries + return SimResult( + equity_curve=[{"date": "2024-01-01", "value": config.initial_capital}], + drawdown_curve=[{"date": "2024-01-01", "value": 0.0}], + trades=[], + per_symbol_stats=[], + stats={"total_return": 0.0, "n_trades": 0}, + ) + + +def test_basic_filter_only_limits_entries_not_panel_rows(): + start = date(2024, 1, 1) + rows = [] + for i, amount in enumerate([1000.0, 0.0, 1000.0]): + rows.append({ + "symbol": "A", + "name": "A", + "date": start + timedelta(days=i), + "open": 10.0 + i, + "high": 10.0 + i, + "low": 10.0 + i, + "close": 10.0 + i, + "volume": 100_000, + "amount": amount, + "signal_limit_up": False, + "signal_limit_down": False, + }) + panel = pl.DataFrame(rows).sort(["symbol", "date"]) + engine = _EngineStub(panel) + service = StrategyBacktestService(engine=engine, strategy_engine=_StrategyEngineStub(_strategy())) + + result = service.run(StrategyBacktestConfig( + strategy_id="test", + symbols=None, + start=start, + end=start + timedelta(days=2), + matching="close_t", + mode="position", + )) + + assert result.error is None + assert engine.sim_panel is not None + assert engine.sim_panel.height == 3 + assert engine.sim_panel.filter(pl.col("amount") == 0.0).height == 1 + assert engine.sim_entries is not None + assert engine.sim_entries.to_list() == [True, False, True] + assert engine.load_args is not None + assert engine.load_args[1] < start # warmup 只用于计算, 不参与正式交易 + + +def test_score_normalizes_inside_strategy_candidate_universe(): + panel = pl.DataFrame({ + "symbol": ["A", "B", "C"], + "date": [date(2024, 1, 1)] * 3, + "factor": [10.0, 20.0, 1000.0], + }) + universe = pl.Series([True, True, False], dtype=pl.Boolean) + strategy = SimpleNamespace(meta={"scoring": {"factor": 1.0}, "order_by": "score", "descending": True}) + + scored = StrategyBacktestService._apply_score(panel, strategy, None, universe_mask=universe) + scores = dict(zip(scored["symbol"].to_list(), scored["score"].to_list())) + + assert scores["A"] == 0.0 + assert scores["B"] == 100.0 + assert scores["C"] == 0.0 + + +def test_full_mode_executes_every_candidate_with_strategy_rules(): + start = date(2024, 1, 1) + panel = pl.DataFrame([ + {"symbol": "A", "name": "A", "date": start, "open": 10.0, "high": 10.0, "low": 10.0, "close": 10.0, "volume": 1, "amount": 1000.0, "signal_limit_up": False, "signal_limit_down": False}, + {"symbol": "A", "name": "A", "date": start + timedelta(days=1), "open": 11.0, "high": 11.0, "low": 11.0, "close": 11.0, "volume": 1, "amount": 0.0, "signal_limit_up": False, "signal_limit_down": False}, + {"symbol": "A", "name": "A", "date": start + timedelta(days=2), "open": 20.0, "high": 20.0, "low": 20.0, "close": 20.0, "volume": 1, "amount": 1000.0, "signal_limit_up": False, "signal_limit_down": False}, + ]).sort(["symbol", "date"]) + + engine = BacktestEngine(repo=None) # type: ignore[arg-type] + engine.load_panel = lambda symbols, s, e: panel # type: ignore[method-assign] + strategy = _strategy( + filter_fn=lambda df, params: pl.col("date") == start, + max_hold_days=1, + ) + service = StrategyBacktestService(engine=engine, strategy_engine=_StrategyEngineStub(strategy)) + + result = service.run(StrategyBacktestConfig( + strategy_id="test", + symbols=None, + start=start, + end=start, + mode="full", + matching="open_t+1", + fees_pct=0, + slippage_bps=0, + holding_days=1, + )) + + assert result.error is None + assert result.stats["full_kind"] == "candidate_execution" + assert result.stats["n_candidates"] == 1 + assert result.stats["n_trades"] == 1 + assert result.trades[0]["entry_date"] == str(start + timedelta(days=1)) + assert result.trades[0]["exit_reason"] == "max_hold" + assert result.stats["avg_return"] == round(20 / 11 - 1, 4) diff --git a/backend/uv.lock b/backend/uv.lock new file mode 100644 index 0000000..dd0f55b --- /dev/null +++ b/backend/uv.lock @@ -0,0 +1,2638 @@ +version = 1 +revision = 3 +requires-python = ">=3.11" +resolution-markers = [ + "python_full_version >= '3.15' and sys_platform == 'win32'", + "python_full_version == '3.14.*' and sys_platform == 'win32'", + "python_full_version >= '3.15' and sys_platform == 'emscripten'", + "python_full_version == '3.14.*' and sys_platform == 'emscripten'", + "python_full_version >= '3.15' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version == '3.14.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version < '3.14' and sys_platform == 'win32'", + "python_full_version < '3.14' and sys_platform == 'emscripten'", + "python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", +] + +[[package]] +name = "annotated-doc" +version = "0.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" }, +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "anyio" +version = "4.13.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/14/2c5dd9f512b66549ae92767a9c7b330ae88e1932ca57876909410251fe13/anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc", size = 231622, upload-time = "2026-03-24T12:59:09.671Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" }, +] + +[[package]] +name = "apscheduler" +version = "3.11.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tzlocal" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/07/12/3e4389e5920b4c1763390c6d371162f3784f86f85cd6d6c1bfe68eef14e2/apscheduler-3.11.2.tar.gz", hash = "sha256:2a9966b052ec805f020c8c4c3ae6e6a06e24b1bf19f2e11d91d8cca0473eef41", size = 108683, upload-time = "2025-12-22T00:39:34.884Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/64/2e54428beba8d9992aa478bb8f6de9e4ecaa5f8f513bcfd567ed7fb0262d/apscheduler-3.11.2-py3-none-any.whl", hash = "sha256:ce005177f741409db4e4dd40a7431b76feb856b9dd69d57e0da49d6715bfd26d", size = 64439, upload-time = "2025-12-22T00:39:33.303Z" }, +] + +[[package]] +name = "ast-serialize" +version = "0.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/81/9d/09e27731bd5864a9ce04e3244074e674bb8936bf62b45e0357248717adac/ast_serialize-0.5.0.tar.gz", hash = "sha256:5880091bfe6f4f986f22866375c2e884843e7a0b6343ae41aeea659613d879b6", size = 61157, upload-time = "2026-05-17T17:48:29.429Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/9a/13dde51ba9e15f8b97957ab7cb0120d0e381524d651c6bd630b9c359227f/ast_serialize-0.5.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8f5c14f169eb0972c0c21bada5358b23d6047c76583b005234f865b11f1fa00a", size = 1183520, upload-time = "2026-05-17T17:47:30.831Z" }, + { url = "https://files.pythonhosted.org/packages/37/de/5a7f0a9fe68944f536632a5af84676739c7d2582be42deb082634bf3a754/ast_serialize-0.5.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7d1a2de9de5be04652f0ed60738356ef94f66db37924a9499fffe98dc491aa0b", size = 1175779, upload-time = "2026-05-17T17:47:32.551Z" }, + { url = "https://files.pythonhosted.org/packages/9c/81/0bb853e76e4f6e9a1855d569003c59e19ffac45f7079d91505d1bb212f92/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be5173fb66f9b49026d9d5a2ff0fc7c7009077107c0eb285b2d60fdf1fe10bd1", size = 1233750, upload-time = "2026-05-17T17:47:34.731Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d3/4cf705beeccc08754d0bbda99aefff26110e209b9a07ac8a6b60eec48531/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f8015cd071ac1339924ee2b8098c93e00e155f30a16f40ec9816fcf84f4753f6", size = 1235942, upload-time = "2026-05-17T17:47:36.287Z" }, + { url = "https://files.pythonhosted.org/packages/26/c8/ee097e437ea27dd2b8b227865c875492b585650a5802a22d82b304c8201b/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5499e8797edff2a9186aa313ed382c6b422e798e9332d9953badcee6e69a88f2", size = 1442517, upload-time = "2026-05-17T17:47:38.17Z" }, + { url = "https://files.pythonhosted.org/packages/ff/bd/68063442838f1ba68ec72b5436430bc75b3bb17a1a3c3063f09b0c05ae2b/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6848f2a093fb5548751a9a09bff8fcd229e2bbeb0e3331f391b6ae6d26cd9903", size = 1254081, upload-time = "2026-05-17T17:47:39.826Z" }, + { url = "https://files.pythonhosted.org/packages/50/e2/1e520793bc6a4e4524a6ab022391e827825eaa0c3811828bfdc6852eca26/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:832d4c998e0b091fd60a6d6bceee535483c4d490de9ba85003af835225719261", size = 1259910, upload-time = "2026-05-17T17:47:41.369Z" }, + { url = "https://files.pythonhosted.org/packages/4e/e1/49b60f467979979cfe6913b43948ff25bca971ad0591d181812f163a988e/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:16db7c62ec0b8efe1d7afd283a388d8f74f2605d56032e5a37747d2de8dba027", size = 1250678, upload-time = "2026-05-17T17:47:43.702Z" }, + { url = "https://files.pythonhosted.org/packages/74/ba/66ab9555de6275677566f6574e5ef6c29cb185ea866f643bc06f8280a8ee/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:baf5eb061eb5bccade4128ad42da33787d72f6013809cd1b590376ece8b3c937", size = 1301603, upload-time = "2026-05-17T17:47:46.256Z" }, + { url = "https://files.pythonhosted.org/packages/66/42/6aca9b9abc710014b2be9059689e5dd1679339e78f567ffb4d255a9e2050/ast_serialize-0.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:104e4a35bd7c124173c41760ef9aaea17ddb3f86c65cb643671d59afbe3ee94c", size = 1410332, upload-time = "2026-05-17T17:47:47.899Z" }, + { url = "https://files.pythonhosted.org/packages/47/68/2f76594432a22581ecf878b5e75a9b8601c24b2241cf0bbeb1e21fcf370c/ast_serialize-0.5.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:36be371028fc1675acb38a331bde160dbab7ff907fdf00b67eb6911aa106951b", size = 1509979, upload-time = "2026-05-17T17:47:50.942Z" }, + { url = "https://files.pythonhosted.org/packages/40/ac/a93c9b58292653f6c595752f677a08e608f903b710594909e9231a389b3b/ast_serialize-0.5.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:061ee58bdb52341c8201a6df41182a977736bae3b7ded87ca7176ca25a8a47ab", size = 1505002, upload-time = "2026-05-17T17:47:54.093Z" }, + { url = "https://files.pythonhosted.org/packages/14/2e/b278f68c497ee2f1d1576cbbef8db5281cd4a5f2db040537592ac9c8862e/ast_serialize-0.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b15219e9cdc9f53f6f4cb51c009203507228226148c05c5e8fe451c28b435eb3", size = 1456231, upload-time = "2026-05-17T17:47:56.311Z" }, + { url = "https://files.pythonhosted.org/packages/0b/43/419be1c566a4c504cd8fd60ce2f84e790f295495c0f327cfaeadf3d51012/ast_serialize-0.5.0-cp314-cp314t-win32.whl", hash = "sha256:842d1c004bb466c7df036f95fabef789570541922b10976b12f5592a69cf0b38", size = 1058668, upload-time = "2026-05-17T17:47:58.305Z" }, + { url = "https://files.pythonhosted.org/packages/03/6f/c9d4d549295ed05111aeb8853232d1afd9d0a179fddb01eeffbb3a4a6842/ast_serialize-0.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b0c06d760909b095cc466356dfccd05a1c7233a6ca191c020dca2c6a6f16c24c", size = 1101075, upload-time = "2026-05-17T17:48:00.35Z" }, + { url = "https://files.pythonhosted.org/packages/d0/8e/d00c5ab30c58222e07d62956fca86c59d91b9ad32997e633c38b526623a3/ast_serialize-0.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:787baedb0262cc49e8ce37cc15c00ae818e46a165a3b36f5e21ed174998104cb", size = 1075347, upload-time = "2026-05-17T17:48:01.753Z" }, + { url = "https://files.pythonhosted.org/packages/e0/9e/dc2530acb3a60dc6e46d65abf27d1d9f86721694757906a148d90a6860de/ast_serialize-0.5.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:0668aa9459cfa8c9c49ddd2163ebcf43088ba045ef7492af6fe22e0098303101", size = 1191380, upload-time = "2026-05-17T17:48:03.738Z" }, + { url = "https://files.pythonhosted.org/packages/26/0a/bd3d18a582f273d6c843d16bb9e22e9e16365ff7991e92f18f798e9f1224/ast_serialize-0.5.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:bf683d6363edf2b39eed6b6d4fe22d34b6203867a67e27134d9e2a2680c4bc4a", size = 1183879, upload-time = "2026-05-17T17:48:05.463Z" }, + { url = "https://files.pythonhosted.org/packages/40/ae/1f919100f8620887af58fcc381c61a1f218cdf89c6e155f87b213e61010a/ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc22cf0c9be65e71cf88fda130af60d61eb4a79370ad4cfe7900d48a4aa2211", size = 1244529, upload-time = "2026-05-17T17:48:07.008Z" }, + { url = "https://files.pythonhosted.org/packages/c6/ca/6376559dcce707cdbc1d0d9a13c8d3baaaa501e949ce0ebdc4230cd881aa/ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f66173891548c9f2726bf27957b41cabce12fa679dc6da505ddbde4d4b3b31cf", size = 1240560, upload-time = "2026-05-17T17:48:08.46Z" }, + { url = "https://files.pythonhosted.org/packages/35/b2/a620e206b5aeb7efbf2710336df57d457cffbb3991076bbcc1147ef9abd4/ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e42d729ef2be96a14efbad355093284739e3670ece3e534f82cc8832790911d9", size = 1451172, upload-time = "2026-05-17T17:48:09.922Z" }, + { url = "https://files.pythonhosted.org/packages/fa/e0/4ad5c04c24a40481b2935ce9a0ccdb6023dc8b667167d06ae530cc3512f2/ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b725026bafa801dbd7310eb13a75f0a2e370e7e51b2cb225f9d21fcfadf919ee", size = 1265072, upload-time = "2026-05-17T17:48:11.469Z" }, + { url = "https://files.pythonhosted.org/packages/b2/71/4d1d479aa56d0101c40e17720c3d6ac2af7269ea0487a80b18e7bfd1a5b7/ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b54f60c1d78767a53b67eaa663f0dfac3afe606aa07f1301572f588b73d64809", size = 1270488, upload-time = "2026-05-17T17:48:13.575Z" }, + { url = "https://files.pythonhosted.org/packages/6d/4f/0de1bbe06f6edef9fde4ed12ca8e7b3ec7e6e2bd4e672c5af487f7957665/ast_serialize-0.5.0-cp39-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:27d51654fc240a1e87e742d353d98eb45b75f62f129086b3596ab53df2ac2a43", size = 1260702, upload-time = "2026-05-17T17:48:15.141Z" }, + { url = "https://files.pythonhosted.org/packages/75/61/e00872439cfdddcc3c1b6cdaa6e5d904ba8e26a18807c67c4e14409d0ca8/ast_serialize-0.5.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c36237c46dd1674542f2109740ea5ea485a169bf1431939ada0434e17934", size = 1311182, upload-time = "2026-05-17T17:48:16.779Z" }, + { url = "https://files.pythonhosted.org/packages/76/8e/699a5b955f7926956c95e9e1d74132acad73c2fe7a426f94da89123c20aa/ast_serialize-0.5.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1943db345233cc7194a470f13afa9c59772c0b123dea0c9414c4d4ca54369759", size = 1421410, upload-time = "2026-05-17T17:48:18.527Z" }, + { url = "https://files.pythonhosted.org/packages/a9/ae/d5b7626874478997adc7a29ab28accf21e596fb590c944290401dfd0b29e/ast_serialize-0.5.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:df1c00022cbbcb064bfaa505aa9c9295362443ce5dacb459d1331d3da353f887", size = 1516587, upload-time = "2026-05-17T17:48:20.133Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ce/b59e02a82d9c4244d64cde502e0b00e83e38816abe19155ceb5437402c7f/ast_serialize-0.5.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:cae65289fc456fde04af979a2be09302ef5d8ab92ef23e596d6746dc267ada27", size = 1515171, upload-time = "2026-05-17T17:48:21.921Z" }, + { url = "https://files.pythonhosted.org/packages/8b/38/d8d90042747d05aa08d4efcf1c99035a5f670a6bf4c214d31644392afbca/ast_serialize-0.5.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:239a4c354e8d676e9d94631d1d4a64edc6b266f86ff3a5a80aedd344f342c01d", size = 1464668, upload-time = "2026-05-17T17:48:23.544Z" }, + { url = "https://files.pythonhosted.org/packages/dd/51/5b840c4df7334104cecffa28f23904fe81ca89ca223d2450e288de39fd3c/ast_serialize-0.5.0-cp39-abi3-win32.whl", hash = "sha256:143a4ef63285a075871908fda3672dc21864b83a8ec3ee12304aa3e4c5387b9a", size = 1068311, upload-time = "2026-05-17T17:48:25.027Z" }, + { url = "https://files.pythonhosted.org/packages/41/11/ca5672c7d491825bc4cd6702dea106a6b60d928707712ec257c7833ae476/ast_serialize-0.5.0-cp39-abi3-win_amd64.whl", hash = "sha256:cf25572c526add400f26a4750dc6ce0c3bb93fc1f75e7ae0cad4ce4f2cd5c590", size = 1108931, upload-time = "2026-05-17T17:48:26.591Z" }, + { url = "https://files.pythonhosted.org/packages/45/19/cc8bd127d28a43da249aa955cfd164cf8fd534e79e42cea96c4854d72fd0/ast_serialize-0.5.0-cp39-abi3-win_arm64.whl", hash = "sha256:92a31c9c20d25a076edaeec76b128a3535d74a24f340b9a8a7e96c9b86dc9642", size = 1081181, upload-time = "2026-05-17T17:48:28.122Z" }, +] + +[[package]] +name = "asttokens" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308, upload-time = "2025-11-15T16:43:48.578Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047, upload-time = "2025-11-15T16:43:16.109Z" }, +] + +[[package]] +name = "certifi" +version = "2026.5.20" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/ce/ee2ecad540810a79593028e88299baeae54d346cc7a0d94b6199988b89b1/certifi-2026.5.20.tar.gz", hash = "sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d", size = 135422, upload-time = "2026-05-20T11:46:50.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/59/8c/57e832b7af6d7c5abe66eb3fbe3a3a32f4d11ea23a1aa7131371035be991/certifi-2026.5.20-py3-none-any.whl", hash = "sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897", size = 134134, upload-time = "2026-05-20T11:46:48.578Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7", size = 309705, upload-time = "2026-04-02T09:26:02.191Z" }, + { url = "https://files.pythonhosted.org/packages/5a/53/58c29116c340e5456724ecd2fff4196d236b98f3da97b404bc5e51ac3493/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7", size = 206419, upload-time = "2026-04-02T09:26:03.583Z" }, + { url = "https://files.pythonhosted.org/packages/b2/02/e8146dc6591a37a00e5144c63f29fb7c97a734ea8a111190783c0e60ab63/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e", size = 227901, upload-time = "2026-04-02T09:26:04.738Z" }, + { url = "https://files.pythonhosted.org/packages/fb/73/77486c4cd58f1267bf17db420e930c9afa1b3be3fe8c8b8ebbebc9624359/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c", size = 222742, upload-time = "2026-04-02T09:26:06.36Z" }, + { url = "https://files.pythonhosted.org/packages/a1/fa/f74eb381a7d94ded44739e9d94de18dc5edc9c17fb8c11f0a6890696c0a9/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df", size = 214061, upload-time = "2026-04-02T09:26:08.347Z" }, + { url = "https://files.pythonhosted.org/packages/dc/92/42bd3cefcf7687253fb86694b45f37b733c97f59af3724f356fa92b8c344/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265", size = 199239, upload-time = "2026-04-02T09:26:09.823Z" }, + { url = "https://files.pythonhosted.org/packages/4c/3d/069e7184e2aa3b3cddc700e3dd267413dc259854adc3380421c805c6a17d/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4", size = 210173, upload-time = "2026-04-02T09:26:10.953Z" }, + { url = "https://files.pythonhosted.org/packages/62/51/9d56feb5f2e7074c46f93e0ebdbe61f0848ee246e2f0d89f8e20b89ebb8f/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e", size = 209841, upload-time = "2026-04-02T09:26:12.142Z" }, + { url = "https://files.pythonhosted.org/packages/d2/59/893d8f99cc4c837dda1fe2f1139079703deb9f321aabcb032355de13b6c7/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38", size = 200304, upload-time = "2026-04-02T09:26:13.711Z" }, + { url = "https://files.pythonhosted.org/packages/7d/1d/ee6f3be3464247578d1ed5c46de545ccc3d3ff933695395c402c21fa6b77/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c", size = 229455, upload-time = "2026-04-02T09:26:14.941Z" }, + { url = "https://files.pythonhosted.org/packages/54/bb/8fb0a946296ea96a488928bdce8ef99023998c48e4713af533e9bb98ef07/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b", size = 210036, upload-time = "2026-04-02T09:26:16.478Z" }, + { url = "https://files.pythonhosted.org/packages/9a/bc/015b2387f913749f82afd4fcba07846d05b6d784dd16123cb66860e0237d/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c", size = 224739, upload-time = "2026-04-02T09:26:17.751Z" }, + { url = "https://files.pythonhosted.org/packages/17/ab/63133691f56baae417493cba6b7c641571a2130eb7bceba6773367ab9ec5/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d", size = 216277, upload-time = "2026-04-02T09:26:18.981Z" }, + { url = "https://files.pythonhosted.org/packages/06/6d/3be70e827977f20db77c12a97e6a9f973631a45b8d186c084527e53e77a4/charset_normalizer-3.4.7-cp311-cp311-win32.whl", hash = "sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad", size = 147819, upload-time = "2026-04-02T09:26:20.295Z" }, + { url = "https://files.pythonhosted.org/packages/20/d9/5f67790f06b735d7c7637171bbfd89882ad67201891b7275e51116ed8207/charset_normalizer-3.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00", size = 159281, upload-time = "2026-04-02T09:26:21.74Z" }, + { url = "https://files.pythonhosted.org/packages/ca/83/6413f36c5a34afead88ce6f66684d943d91f233d76dd083798f9602b75ae/charset_normalizer-3.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1", size = 147843, upload-time = "2026-04-02T09:26:22.901Z" }, + { url = "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46", size = 311328, upload-time = "2026-04-02T09:26:24.331Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e3/0fadc706008ac9d7b9b5be6dc767c05f9d3e5df51744ce4cc9605de7b9f4/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2", size = 208061, upload-time = "2026-04-02T09:26:25.568Z" }, + { url = "https://files.pythonhosted.org/packages/42/f0/3dd1045c47f4a4604df85ec18ad093912ae1344ac706993aff91d38773a2/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b", size = 229031, upload-time = "2026-04-02T09:26:26.865Z" }, + { url = "https://files.pythonhosted.org/packages/dc/67/675a46eb016118a2fbde5a277a5d15f4f69d5f3f5f338e5ee2f8948fcf43/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a", size = 225239, upload-time = "2026-04-02T09:26:28.044Z" }, + { url = "https://files.pythonhosted.org/packages/4b/f8/d0118a2f5f23b02cd166fa385c60f9b0d4f9194f574e2b31cef350ad7223/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116", size = 216589, upload-time = "2026-04-02T09:26:29.239Z" }, + { url = "https://files.pythonhosted.org/packages/b1/f1/6d2b0b261b6c4ceef0fcb0d17a01cc5bc53586c2d4796fa04b5c540bc13d/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb", size = 202733, upload-time = "2026-04-02T09:26:30.5Z" }, + { url = "https://files.pythonhosted.org/packages/6f/c0/7b1f943f7e87cc3db9626ba17807d042c38645f0a1d4415c7a14afb5591f/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1", size = 212652, upload-time = "2026-04-02T09:26:31.709Z" }, + { url = "https://files.pythonhosted.org/packages/38/dd/5a9ab159fe45c6e72079398f277b7d2b523e7f716acc489726115a910097/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15", size = 211229, upload-time = "2026-04-02T09:26:33.282Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ff/531a1cad5ca855d1c1a8b69cb71abfd6d85c0291580146fda7c82857caa1/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5", size = 203552, upload-time = "2026-04-02T09:26:34.845Z" }, + { url = "https://files.pythonhosted.org/packages/c1/4c/a5fb52d528a8ca41f7598cb619409ece30a169fbdf9cdce592e53b46c3a6/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d", size = 230806, upload-time = "2026-04-02T09:26:36.152Z" }, + { url = "https://files.pythonhosted.org/packages/59/7a/071feed8124111a32b316b33ae4de83d36923039ef8cf48120266844285b/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7", size = 212316, upload-time = "2026-04-02T09:26:37.672Z" }, + { url = "https://files.pythonhosted.org/packages/fd/35/f7dba3994312d7ba508e041eaac39a36b120f32d4c8662b8814dab876431/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464", size = 227274, upload-time = "2026-04-02T09:26:38.93Z" }, + { url = "https://files.pythonhosted.org/packages/8a/2d/a572df5c9204ab7688ec1edc895a73ebded3b023bb07364710b05dd1c9be/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49", size = 218468, upload-time = "2026-04-02T09:26:40.17Z" }, + { url = "https://files.pythonhosted.org/packages/86/eb/890922a8b03a568ca2f336c36585a4713c55d4d67bf0f0c78924be6315ca/charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c", size = 148460, upload-time = "2026-04-02T09:26:41.416Z" }, + { url = "https://files.pythonhosted.org/packages/35/d9/0e7dffa06c5ab081f75b1b786f0aefc88365825dfcd0ac544bdb7b2b6853/charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6", size = 159330, upload-time = "2026-04-02T09:26:42.554Z" }, + { url = "https://files.pythonhosted.org/packages/9e/5d/481bcc2a7c88ea6b0878c299547843b2521ccbc40980cb406267088bc701/charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d", size = 147828, upload-time = "2026-04-02T09:26:44.075Z" }, + { url = "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063", size = 309627, upload-time = "2026-04-02T09:26:45.198Z" }, + { url = "https://files.pythonhosted.org/packages/2e/4e/b7f84e617b4854ade48a1b7915c8ccfadeba444d2a18c291f696e37f0d3b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c", size = 207008, upload-time = "2026-04-02T09:26:46.824Z" }, + { url = "https://files.pythonhosted.org/packages/c4/bb/ec73c0257c9e11b268f018f068f5d00aa0ef8c8b09f7753ebd5f2880e248/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66", size = 228303, upload-time = "2026-04-02T09:26:48.397Z" }, + { url = "https://files.pythonhosted.org/packages/85/fb/32d1f5033484494619f701e719429c69b766bfc4dbc61aa9e9c8c166528b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18", size = 224282, upload-time = "2026-04-02T09:26:49.684Z" }, + { url = "https://files.pythonhosted.org/packages/fa/07/330e3a0dda4c404d6da83b327270906e9654a24f6c546dc886a0eb0ffb23/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd", size = 215595, upload-time = "2026-04-02T09:26:50.915Z" }, + { url = "https://files.pythonhosted.org/packages/e3/7c/fc890655786e423f02556e0216d4b8c6bcb6bdfa890160dc66bf52dee468/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215", size = 201986, upload-time = "2026-04-02T09:26:52.197Z" }, + { url = "https://files.pythonhosted.org/packages/d8/97/bfb18b3db2aed3b90cf54dc292ad79fdd5ad65c4eae454099475cbeadd0d/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859", size = 211711, upload-time = "2026-04-02T09:26:53.49Z" }, + { url = "https://files.pythonhosted.org/packages/6f/a5/a581c13798546a7fd557c82614a5c65a13df2157e9ad6373166d2a3e645d/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8", size = 210036, upload-time = "2026-04-02T09:26:54.975Z" }, + { url = "https://files.pythonhosted.org/packages/8c/bf/b3ab5bcb478e4193d517644b0fb2bf5497fbceeaa7a1bc0f4d5b50953861/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5", size = 202998, upload-time = "2026-04-02T09:26:56.303Z" }, + { url = "https://files.pythonhosted.org/packages/e7/4e/23efd79b65d314fa320ec6017b4b5834d5c12a58ba4610aa353af2e2f577/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832", size = 230056, upload-time = "2026-04-02T09:26:57.554Z" }, + { url = "https://files.pythonhosted.org/packages/b9/9f/1e1941bc3f0e01df116e68dc37a55c4d249df5e6fa77f008841aef68264f/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6", size = 211537, upload-time = "2026-04-02T09:26:58.843Z" }, + { url = "https://files.pythonhosted.org/packages/80/0f/088cbb3020d44428964a6c97fe1edfb1b9550396bf6d278330281e8b709c/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48", size = 226176, upload-time = "2026-04-02T09:27:00.437Z" }, + { url = "https://files.pythonhosted.org/packages/6a/9f/130394f9bbe06f4f63e22641d32fc9b202b7e251c9aef4db044324dac493/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a", size = 217723, upload-time = "2026-04-02T09:27:02.021Z" }, + { url = "https://files.pythonhosted.org/packages/73/55/c469897448a06e49f8fa03f6caae97074fde823f432a98f979cc42b90e69/charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e", size = 148085, upload-time = "2026-04-02T09:27:03.192Z" }, + { url = "https://files.pythonhosted.org/packages/5d/78/1b74c5bbb3f99b77a1715c91b3e0b5bdb6fe302d95ace4f5b1bec37b0167/charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110", size = 158819, upload-time = "2026-04-02T09:27:04.454Z" }, + { url = "https://files.pythonhosted.org/packages/68/86/46bd42279d323deb8687c4a5a811fd548cb7d1de10cf6535d099877a9a9f/charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b", size = 147915, upload-time = "2026-04-02T09:27:05.971Z" }, + { url = "https://files.pythonhosted.org/packages/97/c8/c67cb8c70e19ef1960b97b22ed2a1567711de46c4ddf19799923adc836c2/charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0", size = 309234, upload-time = "2026-04-02T09:27:07.194Z" }, + { url = "https://files.pythonhosted.org/packages/99/85/c091fdee33f20de70d6c8b522743b6f831a2f1cd3ff86de4c6a827c48a76/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a", size = 208042, upload-time = "2026-04-02T09:27:08.749Z" }, + { url = "https://files.pythonhosted.org/packages/87/1c/ab2ce611b984d2fd5d86a5a8a19c1ae26acac6bad967da4967562c75114d/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b", size = 228706, upload-time = "2026-04-02T09:27:09.951Z" }, + { url = "https://files.pythonhosted.org/packages/a8/29/2b1d2cb00bf085f59d29eb773ce58ec2d325430f8c216804a0a5cd83cbca/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41", size = 224727, upload-time = "2026-04-02T09:27:11.175Z" }, + { url = "https://files.pythonhosted.org/packages/47/5c/032c2d5a07fe4d4855fea851209cca2b6f03ebeb6d4e3afdb3358386a684/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e", size = 215882, upload-time = "2026-04-02T09:27:12.446Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c2/356065d5a8b78ed04499cae5f339f091946a6a74f91e03476c33f0ab7100/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae", size = 200860, upload-time = "2026-04-02T09:27:13.721Z" }, + { url = "https://files.pythonhosted.org/packages/0c/cd/a32a84217ced5039f53b29f460962abb2d4420def55afabe45b1c3c7483d/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18", size = 211564, upload-time = "2026-04-02T09:27:15.272Z" }, + { url = "https://files.pythonhosted.org/packages/44/86/58e6f13ce26cc3b8f4a36b94a0f22ae2f00a72534520f4ae6857c4b81f89/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b", size = 211276, upload-time = "2026-04-02T09:27:16.834Z" }, + { url = "https://files.pythonhosted.org/packages/8f/fe/d17c32dc72e17e155e06883efa84514ca375f8a528ba2546bee73fc4df81/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356", size = 201238, upload-time = "2026-04-02T09:27:18.229Z" }, + { url = "https://files.pythonhosted.org/packages/6a/29/f33daa50b06525a237451cdb6c69da366c381a3dadcd833fa5676bc468b3/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab", size = 230189, upload-time = "2026-04-02T09:27:19.445Z" }, + { url = "https://files.pythonhosted.org/packages/b6/6e/52c84015394a6a0bdcd435210a7e944c5f94ea1055f5cc5d56c5fe368e7b/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46", size = 211352, upload-time = "2026-04-02T09:27:20.79Z" }, + { url = "https://files.pythonhosted.org/packages/8c/d7/4353be581b373033fb9198bf1da3cf8f09c1082561e8e922aa7b39bf9fe8/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44", size = 227024, upload-time = "2026-04-02T09:27:22.063Z" }, + { url = "https://files.pythonhosted.org/packages/30/45/99d18aa925bd1740098ccd3060e238e21115fffbfdcb8f3ece837d0ace6c/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72", size = 217869, upload-time = "2026-04-02T09:27:23.486Z" }, + { url = "https://files.pythonhosted.org/packages/5c/05/5ee478aa53f4bb7996482153d4bfe1b89e0f087f0ab6b294fcf92d595873/charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10", size = 148541, upload-time = "2026-04-02T09:27:25.146Z" }, + { url = "https://files.pythonhosted.org/packages/48/77/72dcb0921b2ce86420b2d79d454c7022bf5be40202a2a07906b9f2a35c97/charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f", size = 159634, upload-time = "2026-04-02T09:27:26.642Z" }, + { url = "https://files.pythonhosted.org/packages/c6/a3/c2369911cd72f02386e4e340770f6e158c7980267da16af8f668217abaa0/charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246", size = 148384, upload-time = "2026-04-02T09:27:28.271Z" }, + { url = "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24", size = 330133, upload-time = "2026-04-02T09:27:29.474Z" }, + { url = "https://files.pythonhosted.org/packages/8d/da/96975ddb11f8e977f706f45cddd8540fd8242f71ecdb5d18a80723dcf62c/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79", size = 216257, upload-time = "2026-04-02T09:27:30.793Z" }, + { url = "https://files.pythonhosted.org/packages/e5/e8/1d63bf8ef2d388e95c64b2098f45f84758f6d102a087552da1485912637b/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960", size = 234851, upload-time = "2026-04-02T09:27:32.44Z" }, + { url = "https://files.pythonhosted.org/packages/9b/40/e5ff04233e70da2681fa43969ad6f66ca5611d7e669be0246c4c7aaf6dc8/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4", size = 233393, upload-time = "2026-04-02T09:27:34.03Z" }, + { url = "https://files.pythonhosted.org/packages/be/c1/06c6c49d5a5450f76899992f1ee40b41d076aee9279b49cf9974d2f313d5/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e", size = 223251, upload-time = "2026-04-02T09:27:35.369Z" }, + { url = "https://files.pythonhosted.org/packages/2b/9f/f2ff16fb050946169e3e1f82134d107e5d4ae72647ec8a1b1446c148480f/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1", size = 206609, upload-time = "2026-04-02T09:27:36.661Z" }, + { url = "https://files.pythonhosted.org/packages/69/d5/a527c0cd8d64d2eab7459784fb4169a0ac76e5a6fc5237337982fd61347e/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44", size = 220014, upload-time = "2026-04-02T09:27:38.019Z" }, + { url = "https://files.pythonhosted.org/packages/7e/80/8a7b8104a3e203074dc9aa2c613d4b726c0e136bad1cc734594b02867972/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e", size = 218979, upload-time = "2026-04-02T09:27:39.37Z" }, + { url = "https://files.pythonhosted.org/packages/02/9a/b759b503d507f375b2b5c153e4d2ee0a75aa215b7f2489cf314f4541f2c0/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3", size = 209238, upload-time = "2026-04-02T09:27:40.722Z" }, + { url = "https://files.pythonhosted.org/packages/c2/4e/0f3f5d47b86bdb79256e7290b26ac847a2832d9a4033f7eb2cd4bcf4bb5b/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0", size = 236110, upload-time = "2026-04-02T09:27:42.33Z" }, + { url = "https://files.pythonhosted.org/packages/96/23/bce28734eb3ed2c91dcf93abeb8a5cf393a7b2749725030bb630e554fdd8/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e", size = 219824, upload-time = "2026-04-02T09:27:43.924Z" }, + { url = "https://files.pythonhosted.org/packages/2c/6f/6e897c6984cc4d41af319b077f2f600fc8214eb2fe2d6bcb79141b882400/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb", size = 233103, upload-time = "2026-04-02T09:27:45.348Z" }, + { url = "https://files.pythonhosted.org/packages/76/22/ef7bd0fe480a0ae9b656189ec00744b60933f68b4f42a7bb06589f6f576a/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe", size = 225194, upload-time = "2026-04-02T09:27:46.706Z" }, + { url = "https://files.pythonhosted.org/packages/c5/a7/0e0ab3e0b5bc1219bd80a6a0d4d72ca74d9250cb2382b7c699c147e06017/charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0", size = 159827, upload-time = "2026-04-02T09:27:48.053Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1d/29d32e0fb40864b1f878c7f5a0b343ae676c6e2b271a2d55cc3a152391da/charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c", size = 174168, upload-time = "2026-04-02T09:27:49.795Z" }, + { url = "https://files.pythonhosted.org/packages/de/32/d92444ad05c7a6e41fb2036749777c163baf7a0301a040cb672d6b2b1ae9/charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d", size = 153018, upload-time = "2026-04-02T09:27:51.116Z" }, + { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" }, +] + +[[package]] +name = "click" +version = "8.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9b/98/518d8e5081007684232226f475082b30087d0f585e8457db087298259f49/click-8.4.1.tar.gz", hash = "sha256:918b5633eddf6b41c32d4f454bf0de810065c74e3f7dbf8ee5452f8be88d3e96", size = 353007, upload-time = "2026-05-22T04:08:37.769Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/0d/67e5b4109ea4a837e80daa87c2c696711955e40449a97e8926672534def2/click-8.4.1-py3-none-any.whl", hash = "sha256:482be17c6991b8c19c5429a1e995d9b0efdbb63172824c41f99965dc0ade8ec2", size = 116639, upload-time = "2026-05-22T04:08:35.26Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "comm" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319, upload-time = "2025-07-25T14:02:04.452Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294, upload-time = "2025-07-25T14:02:02.896Z" }, +] + +[[package]] +name = "contourpy" +version = "1.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/2e/c4390a31919d8a78b90e8ecf87cd4b4c4f05a5b48d05ec17db8e5404c6f4/contourpy-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:709a48ef9a690e1343202916450bc48b9e51c049b089c7f79a267b46cffcdaa1", size = 288773, upload-time = "2025-07-26T12:01:02.277Z" }, + { url = "https://files.pythonhosted.org/packages/0d/44/c4b0b6095fef4dc9c420e041799591e3b63e9619e3044f7f4f6c21c0ab24/contourpy-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:23416f38bfd74d5d28ab8429cc4d63fa67d5068bd711a85edb1c3fb0c3e2f381", size = 270149, upload-time = "2025-07-26T12:01:04.072Z" }, + { url = "https://files.pythonhosted.org/packages/30/2e/dd4ced42fefac8470661d7cb7e264808425e6c5d56d175291e93890cce09/contourpy-1.3.3-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:929ddf8c4c7f348e4c0a5a3a714b5c8542ffaa8c22954862a46ca1813b667ee7", size = 329222, upload-time = "2025-07-26T12:01:05.688Z" }, + { url = "https://files.pythonhosted.org/packages/f2/74/cc6ec2548e3d276c71389ea4802a774b7aa3558223b7bade3f25787fafc2/contourpy-1.3.3-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9e999574eddae35f1312c2b4b717b7885d4edd6cb46700e04f7f02db454e67c1", size = 377234, upload-time = "2025-07-26T12:01:07.054Z" }, + { url = "https://files.pythonhosted.org/packages/03/b3/64ef723029f917410f75c09da54254c5f9ea90ef89b143ccadb09df14c15/contourpy-1.3.3-cp311-cp311-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf67e0e3f482cb69779dd3061b534eb35ac9b17f163d851e2a547d56dba0a3a", size = 380555, upload-time = "2025-07-26T12:01:08.801Z" }, + { url = "https://files.pythonhosted.org/packages/5f/4b/6157f24ca425b89fe2eb7e7be642375711ab671135be21e6faa100f7448c/contourpy-1.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:51e79c1f7470158e838808d4a996fa9bac72c498e93d8ebe5119bc1e6becb0db", size = 355238, upload-time = "2025-07-26T12:01:10.319Z" }, + { url = "https://files.pythonhosted.org/packages/98/56/f914f0dd678480708a04cfd2206e7c382533249bc5001eb9f58aa693e200/contourpy-1.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:598c3aaece21c503615fd59c92a3598b428b2f01bfb4b8ca9c4edeecc2438620", size = 1326218, upload-time = "2025-07-26T12:01:12.659Z" }, + { url = "https://files.pythonhosted.org/packages/fb/d7/4a972334a0c971acd5172389671113ae82aa7527073980c38d5868ff1161/contourpy-1.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:322ab1c99b008dad206d406bb61d014cf0174df491ae9d9d0fac6a6fda4f977f", size = 1392867, upload-time = "2025-07-26T12:01:15.533Z" }, + { url = "https://files.pythonhosted.org/packages/75/3e/f2cc6cd56dc8cff46b1a56232eabc6feea52720083ea71ab15523daab796/contourpy-1.3.3-cp311-cp311-win32.whl", hash = "sha256:fd907ae12cd483cd83e414b12941c632a969171bf90fc937d0c9f268a31cafff", size = 183677, upload-time = "2025-07-26T12:01:17.088Z" }, + { url = "https://files.pythonhosted.org/packages/98/4b/9bd370b004b5c9d8045c6c33cf65bae018b27aca550a3f657cdc99acdbd8/contourpy-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:3519428f6be58431c56581f1694ba8e50626f2dd550af225f82fb5f5814d2a42", size = 225234, upload-time = "2025-07-26T12:01:18.256Z" }, + { url = "https://files.pythonhosted.org/packages/d9/b6/71771e02c2e004450c12b1120a5f488cad2e4d5b590b1af8bad060360fe4/contourpy-1.3.3-cp311-cp311-win_arm64.whl", hash = "sha256:15ff10bfada4bf92ec8b31c62bf7c1834c244019b4a33095a68000d7075df470", size = 193123, upload-time = "2025-07-26T12:01:19.848Z" }, + { url = "https://files.pythonhosted.org/packages/be/45/adfee365d9ea3d853550b2e735f9d66366701c65db7855cd07621732ccfc/contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb", size = 293419, upload-time = "2025-07-26T12:01:21.16Z" }, + { url = "https://files.pythonhosted.org/packages/53/3e/405b59cfa13021a56bba395a6b3aca8cec012b45bf177b0eaf7a202cde2c/contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6", size = 273979, upload-time = "2025-07-26T12:01:22.448Z" }, + { url = "https://files.pythonhosted.org/packages/d4/1c/a12359b9b2ca3a845e8f7f9ac08bdf776114eb931392fcad91743e2ea17b/contourpy-1.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7", size = 332653, upload-time = "2025-07-26T12:01:24.155Z" }, + { url = "https://files.pythonhosted.org/packages/63/12/897aeebfb475b7748ea67b61e045accdfcf0d971f8a588b67108ed7f5512/contourpy-1.3.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8", size = 379536, upload-time = "2025-07-26T12:01:25.91Z" }, + { url = "https://files.pythonhosted.org/packages/43/8a/a8c584b82deb248930ce069e71576fc09bd7174bbd35183b7943fb1064fd/contourpy-1.3.3-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea", size = 384397, upload-time = "2025-07-26T12:01:27.152Z" }, + { url = "https://files.pythonhosted.org/packages/cc/8f/ec6289987824b29529d0dfda0d74a07cec60e54b9c92f3c9da4c0ac732de/contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1", size = 362601, upload-time = "2025-07-26T12:01:28.808Z" }, + { url = "https://files.pythonhosted.org/packages/05/0a/a3fe3be3ee2dceb3e615ebb4df97ae6f3828aa915d3e10549ce016302bd1/contourpy-1.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7", size = 1331288, upload-time = "2025-07-26T12:01:31.198Z" }, + { url = "https://files.pythonhosted.org/packages/33/1d/acad9bd4e97f13f3e2b18a3977fe1b4a37ecf3d38d815333980c6c72e963/contourpy-1.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411", size = 1403386, upload-time = "2025-07-26T12:01:33.947Z" }, + { url = "https://files.pythonhosted.org/packages/cf/8f/5847f44a7fddf859704217a99a23a4f6417b10e5ab1256a179264561540e/contourpy-1.3.3-cp312-cp312-win32.whl", hash = "sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69", size = 185018, upload-time = "2025-07-26T12:01:35.64Z" }, + { url = "https://files.pythonhosted.org/packages/19/e8/6026ed58a64563186a9ee3f29f41261fd1828f527dd93d33b60feca63352/contourpy-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b", size = 226567, upload-time = "2025-07-26T12:01:36.804Z" }, + { url = "https://files.pythonhosted.org/packages/d1/e2/f05240d2c39a1ed228d8328a78b6f44cd695f7ef47beb3e684cf93604f86/contourpy-1.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc", size = 193655, upload-time = "2025-07-26T12:01:37.999Z" }, + { url = "https://files.pythonhosted.org/packages/68/35/0167aad910bbdb9599272bd96d01a9ec6852f36b9455cf2ca67bd4cc2d23/contourpy-1.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:177fb367556747a686509d6fef71d221a4b198a3905fe824430e5ea0fda54eb5", size = 293257, upload-time = "2025-07-26T12:01:39.367Z" }, + { url = "https://files.pythonhosted.org/packages/96/e4/7adcd9c8362745b2210728f209bfbcf7d91ba868a2c5f40d8b58f54c509b/contourpy-1.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d002b6f00d73d69333dac9d0b8d5e84d9724ff9ef044fd63c5986e62b7c9e1b1", size = 274034, upload-time = "2025-07-26T12:01:40.645Z" }, + { url = "https://files.pythonhosted.org/packages/73/23/90e31ceeed1de63058a02cb04b12f2de4b40e3bef5e082a7c18d9c8ae281/contourpy-1.3.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:348ac1f5d4f1d66d3322420f01d42e43122f43616e0f194fc1c9f5d830c5b286", size = 334672, upload-time = "2025-07-26T12:01:41.942Z" }, + { url = "https://files.pythonhosted.org/packages/ed/93/b43d8acbe67392e659e1d984700e79eb67e2acb2bd7f62012b583a7f1b55/contourpy-1.3.3-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:655456777ff65c2c548b7c454af9c6f33f16c8884f11083244b5819cc214f1b5", size = 381234, upload-time = "2025-07-26T12:01:43.499Z" }, + { url = "https://files.pythonhosted.org/packages/46/3b/bec82a3ea06f66711520f75a40c8fc0b113b2a75edb36aa633eb11c4f50f/contourpy-1.3.3-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:644a6853d15b2512d67881586bd03f462c7ab755db95f16f14d7e238f2852c67", size = 385169, upload-time = "2025-07-26T12:01:45.219Z" }, + { url = "https://files.pythonhosted.org/packages/4b/32/e0f13a1c5b0f8572d0ec6ae2f6c677b7991fafd95da523159c19eff0696a/contourpy-1.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4debd64f124ca62069f313a9cb86656ff087786016d76927ae2cf37846b006c9", size = 362859, upload-time = "2025-07-26T12:01:46.519Z" }, + { url = "https://files.pythonhosted.org/packages/33/71/e2a7945b7de4e58af42d708a219f3b2f4cff7386e6b6ab0a0fa0033c49a9/contourpy-1.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a15459b0f4615b00bbd1e91f1b9e19b7e63aea7483d03d804186f278c0af2659", size = 1332062, upload-time = "2025-07-26T12:01:48.964Z" }, + { url = "https://files.pythonhosted.org/packages/12/fc/4e87ac754220ccc0e807284f88e943d6d43b43843614f0a8afa469801db0/contourpy-1.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca0fdcd73925568ca027e0b17ab07aad764be4706d0a925b89227e447d9737b7", size = 1403932, upload-time = "2025-07-26T12:01:51.979Z" }, + { url = "https://files.pythonhosted.org/packages/a6/2e/adc197a37443f934594112222ac1aa7dc9a98faf9c3842884df9a9d8751d/contourpy-1.3.3-cp313-cp313-win32.whl", hash = "sha256:b20c7c9a3bf701366556e1b1984ed2d0cedf999903c51311417cf5f591d8c78d", size = 185024, upload-time = "2025-07-26T12:01:53.245Z" }, + { url = "https://files.pythonhosted.org/packages/18/0b/0098c214843213759692cc638fce7de5c289200a830e5035d1791d7a2338/contourpy-1.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:1cadd8b8969f060ba45ed7c1b714fe69185812ab43bd6b86a9123fe8f99c3263", size = 226578, upload-time = "2025-07-26T12:01:54.422Z" }, + { url = "https://files.pythonhosted.org/packages/8a/9a/2f6024a0c5995243cd63afdeb3651c984f0d2bc727fd98066d40e141ad73/contourpy-1.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:fd914713266421b7536de2bfa8181aa8c699432b6763a0ea64195ebe28bff6a9", size = 193524, upload-time = "2025-07-26T12:01:55.73Z" }, + { url = "https://files.pythonhosted.org/packages/c0/b3/f8a1a86bd3298513f500e5b1f5fd92b69896449f6cab6a146a5d52715479/contourpy-1.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:88df9880d507169449d434c293467418b9f6cbe82edd19284aa0409e7fdb933d", size = 306730, upload-time = "2025-07-26T12:01:57.051Z" }, + { url = "https://files.pythonhosted.org/packages/3f/11/4780db94ae62fc0c2053909b65dc3246bd7cecfc4f8a20d957ad43aa4ad8/contourpy-1.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d06bb1f751ba5d417047db62bca3c8fde202b8c11fb50742ab3ab962c81e8216", size = 287897, upload-time = "2025-07-26T12:01:58.663Z" }, + { url = "https://files.pythonhosted.org/packages/ae/15/e59f5f3ffdd6f3d4daa3e47114c53daabcb18574a26c21f03dc9e4e42ff0/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e4e6b05a45525357e382909a4c1600444e2a45b4795163d3b22669285591c1ae", size = 326751, upload-time = "2025-07-26T12:02:00.343Z" }, + { url = "https://files.pythonhosted.org/packages/0f/81/03b45cfad088e4770b1dcf72ea78d3802d04200009fb364d18a493857210/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ab3074b48c4e2cf1a960e6bbeb7f04566bf36b1861d5c9d4d8ac04b82e38ba20", size = 375486, upload-time = "2025-07-26T12:02:02.128Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ba/49923366492ffbdd4486e970d421b289a670ae8cf539c1ea9a09822b371a/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c3d53c796f8647d6deb1abe867daeb66dcc8a97e8455efa729516b997b8ed99", size = 388106, upload-time = "2025-07-26T12:02:03.615Z" }, + { url = "https://files.pythonhosted.org/packages/9f/52/5b00ea89525f8f143651f9f03a0df371d3cbd2fccd21ca9b768c7a6500c2/contourpy-1.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50ed930df7289ff2a8d7afeb9603f8289e5704755c7e5c3bbd929c90c817164b", size = 352548, upload-time = "2025-07-26T12:02:05.165Z" }, + { url = "https://files.pythonhosted.org/packages/32/1d/a209ec1a3a3452d490f6b14dd92e72280c99ae3d1e73da74f8277d4ee08f/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4feffb6537d64b84877da813a5c30f1422ea5739566abf0bd18065ac040e120a", size = 1322297, upload-time = "2025-07-26T12:02:07.379Z" }, + { url = "https://files.pythonhosted.org/packages/bc/9e/46f0e8ebdd884ca0e8877e46a3f4e633f6c9c8c4f3f6e72be3fe075994aa/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2b7e9480ffe2b0cd2e787e4df64270e3a0440d9db8dc823312e2c940c167df7e", size = 1391023, upload-time = "2025-07-26T12:02:10.171Z" }, + { url = "https://files.pythonhosted.org/packages/b9/70/f308384a3ae9cd2209e0849f33c913f658d3326900d0ff5d378d6a1422d2/contourpy-1.3.3-cp313-cp313t-win32.whl", hash = "sha256:283edd842a01e3dcd435b1c5116798d661378d83d36d337b8dde1d16a5fc9ba3", size = 196157, upload-time = "2025-07-26T12:02:11.488Z" }, + { url = "https://files.pythonhosted.org/packages/b2/dd/880f890a6663b84d9e34a6f88cded89d78f0091e0045a284427cb6b18521/contourpy-1.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:87acf5963fc2b34825e5b6b048f40e3635dd547f590b04d2ab317c2619ef7ae8", size = 240570, upload-time = "2025-07-26T12:02:12.754Z" }, + { url = "https://files.pythonhosted.org/packages/80/99/2adc7d8ffead633234817ef8e9a87115c8a11927a94478f6bb3d3f4d4f7d/contourpy-1.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:3c30273eb2a55024ff31ba7d052dde990d7d8e5450f4bbb6e913558b3d6c2301", size = 199713, upload-time = "2025-07-26T12:02:14.4Z" }, + { url = "https://files.pythonhosted.org/packages/72/8b/4546f3ab60f78c514ffb7d01a0bd743f90de36f0019d1be84d0a708a580a/contourpy-1.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fde6c716d51c04b1c25d0b90364d0be954624a0ee9d60e23e850e8d48353d07a", size = 292189, upload-time = "2025-07-26T12:02:16.095Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e1/3542a9cb596cadd76fcef413f19c79216e002623158befe6daa03dbfa88c/contourpy-1.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cbedb772ed74ff5be440fa8eee9bd49f64f6e3fc09436d9c7d8f1c287b121d77", size = 273251, upload-time = "2025-07-26T12:02:17.524Z" }, + { url = "https://files.pythonhosted.org/packages/b1/71/f93e1e9471d189f79d0ce2497007731c1e6bf9ef6d1d61b911430c3db4e5/contourpy-1.3.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22e9b1bd7a9b1d652cd77388465dc358dafcd2e217d35552424aa4f996f524f5", size = 335810, upload-time = "2025-07-26T12:02:18.9Z" }, + { url = "https://files.pythonhosted.org/packages/91/f9/e35f4c1c93f9275d4e38681a80506b5510e9327350c51f8d4a5a724d178c/contourpy-1.3.3-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a22738912262aa3e254e4f3cb079a95a67132fc5a063890e224393596902f5a4", size = 382871, upload-time = "2025-07-26T12:02:20.418Z" }, + { url = "https://files.pythonhosted.org/packages/b5/71/47b512f936f66a0a900d81c396a7e60d73419868fba959c61efed7a8ab46/contourpy-1.3.3-cp314-cp314-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:afe5a512f31ee6bd7d0dda52ec9864c984ca3d66664444f2d72e0dc4eb832e36", size = 386264, upload-time = "2025-07-26T12:02:21.916Z" }, + { url = "https://files.pythonhosted.org/packages/04/5f/9ff93450ba96b09c7c2b3f81c94de31c89f92292f1380261bd7195bea4ea/contourpy-1.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f64836de09927cba6f79dcd00fdd7d5329f3fccc633468507079c829ca4db4e3", size = 363819, upload-time = "2025-07-26T12:02:23.759Z" }, + { url = "https://files.pythonhosted.org/packages/3e/a6/0b185d4cc480ee494945cde102cb0149ae830b5fa17bf855b95f2e70ad13/contourpy-1.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1fd43c3be4c8e5fd6e4f2baeae35ae18176cf2e5cced681cca908addf1cdd53b", size = 1333650, upload-time = "2025-07-26T12:02:26.181Z" }, + { url = "https://files.pythonhosted.org/packages/43/d7/afdc95580ca56f30fbcd3060250f66cedbde69b4547028863abd8aa3b47e/contourpy-1.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6afc576f7b33cf00996e5c1102dc2a8f7cc89e39c0b55df93a0b78c1bd992b36", size = 1404833, upload-time = "2025-07-26T12:02:28.782Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e2/366af18a6d386f41132a48f033cbd2102e9b0cf6345d35ff0826cd984566/contourpy-1.3.3-cp314-cp314-win32.whl", hash = "sha256:66c8a43a4f7b8df8b71ee1840e4211a3c8d93b214b213f590e18a1beca458f7d", size = 189692, upload-time = "2025-07-26T12:02:30.128Z" }, + { url = "https://files.pythonhosted.org/packages/7d/c2/57f54b03d0f22d4044b8afb9ca0e184f8b1afd57b4f735c2fa70883dc601/contourpy-1.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:cf9022ef053f2694e31d630feaacb21ea24224be1c3ad0520b13d844274614fd", size = 232424, upload-time = "2025-07-26T12:02:31.395Z" }, + { url = "https://files.pythonhosted.org/packages/18/79/a9416650df9b525737ab521aa181ccc42d56016d2123ddcb7b58e926a42c/contourpy-1.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:95b181891b4c71de4bb404c6621e7e2390745f887f2a026b2d99e92c17892339", size = 198300, upload-time = "2025-07-26T12:02:32.956Z" }, + { url = "https://files.pythonhosted.org/packages/1f/42/38c159a7d0f2b7b9c04c64ab317042bb6952b713ba875c1681529a2932fe/contourpy-1.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:33c82d0138c0a062380332c861387650c82e4cf1747aaa6938b9b6516762e772", size = 306769, upload-time = "2025-07-26T12:02:34.2Z" }, + { url = "https://files.pythonhosted.org/packages/c3/6c/26a8205f24bca10974e77460de68d3d7c63e282e23782f1239f226fcae6f/contourpy-1.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ea37e7b45949df430fe649e5de8351c423430046a2af20b1c1961cae3afcda77", size = 287892, upload-time = "2025-07-26T12:02:35.807Z" }, + { url = "https://files.pythonhosted.org/packages/66/06/8a475c8ab718ebfd7925661747dbb3c3ee9c82ac834ccb3570be49d129f4/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d304906ecc71672e9c89e87c4675dc5c2645e1f4269a5063b99b0bb29f232d13", size = 326748, upload-time = "2025-07-26T12:02:37.193Z" }, + { url = "https://files.pythonhosted.org/packages/b4/a3/c5ca9f010a44c223f098fccd8b158bb1cb287378a31ac141f04730dc49be/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca658cd1a680a5c9ea96dc61cdbae1e85c8f25849843aa799dfd3cb370ad4fbe", size = 375554, upload-time = "2025-07-26T12:02:38.894Z" }, + { url = "https://files.pythonhosted.org/packages/80/5b/68bd33ae63fac658a4145088c1e894405e07584a316738710b636c6d0333/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ab2fd90904c503739a75b7c8c5c01160130ba67944a7b77bbf36ef8054576e7f", size = 388118, upload-time = "2025-07-26T12:02:40.642Z" }, + { url = "https://files.pythonhosted.org/packages/40/52/4c285a6435940ae25d7410a6c36bda5145839bc3f0beb20c707cda18b9d2/contourpy-1.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7301b89040075c30e5768810bc96a8e8d78085b47d8be6e4c3f5a0b4ed478a0", size = 352555, upload-time = "2025-07-26T12:02:42.25Z" }, + { url = "https://files.pythonhosted.org/packages/24/ee/3e81e1dd174f5c7fefe50e85d0892de05ca4e26ef1c9a59c2a57e43b865a/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2a2a8b627d5cc6b7c41a4beff6c5ad5eb848c88255fda4a8745f7e901b32d8e4", size = 1322295, upload-time = "2025-07-26T12:02:44.668Z" }, + { url = "https://files.pythonhosted.org/packages/3c/b2/6d913d4d04e14379de429057cd169e5e00f6c2af3bb13e1710bcbdb5da12/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fd6ec6be509c787f1caf6b247f0b1ca598bef13f4ddeaa126b7658215529ba0f", size = 1391027, upload-time = "2025-07-26T12:02:47.09Z" }, + { url = "https://files.pythonhosted.org/packages/93/8a/68a4ec5c55a2971213d29a9374913f7e9f18581945a7a31d1a39b5d2dfe5/contourpy-1.3.3-cp314-cp314t-win32.whl", hash = "sha256:e74a9a0f5e3fff48fb5a7f2fd2b9b70a3fe014a67522f79b7cca4c0c7e43c9ae", size = 202428, upload-time = "2025-07-26T12:02:48.691Z" }, + { url = "https://files.pythonhosted.org/packages/fa/96/fd9f641ffedc4fa3ace923af73b9d07e869496c9cc7a459103e6e978992f/contourpy-1.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:13b68d6a62db8eafaebb8039218921399baf6e47bf85006fd8529f2a08ef33fc", size = 250331, upload-time = "2025-07-26T12:02:50.137Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8c/469afb6465b853afff216f9528ffda78a915ff880ed58813ba4faf4ba0b6/contourpy-1.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:b7448cb5a725bb1e35ce88771b86fba35ef418952474492cf7c764059933ff8b", size = 203831, upload-time = "2025-07-26T12:02:51.449Z" }, + { url = "https://files.pythonhosted.org/packages/a5/29/8dcfe16f0107943fa92388c23f6e05cff0ba58058c4c95b00280d4c75a14/contourpy-1.3.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cd5dfcaeb10f7b7f9dc8941717c6c2ade08f587be2226222c12b25f0483ed497", size = 278809, upload-time = "2025-07-26T12:02:52.74Z" }, + { url = "https://files.pythonhosted.org/packages/85/a9/8b37ef4f7dafeb335daee3c8254645ef5725be4d9c6aa70b50ec46ef2f7e/contourpy-1.3.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:0c1fc238306b35f246d61a1d416a627348b5cf0648648a031e14bb8705fcdfe8", size = 261593, upload-time = "2025-07-26T12:02:54.037Z" }, + { url = "https://files.pythonhosted.org/packages/0a/59/ebfb8c677c75605cc27f7122c90313fd2f375ff3c8d19a1694bda74aaa63/contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:70f9aad7de812d6541d29d2bbf8feb22ff7e1c299523db288004e3157ff4674e", size = 302202, upload-time = "2025-07-26T12:02:55.947Z" }, + { url = "https://files.pythonhosted.org/packages/3c/37/21972a15834d90bfbfb009b9d004779bd5a07a0ec0234e5ba8f64d5736f4/contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ed3657edf08512fc3fe81b510e35c2012fbd3081d2e26160f27ca28affec989", size = 329207, upload-time = "2025-07-26T12:02:57.468Z" }, + { url = "https://files.pythonhosted.org/packages/0c/58/bd257695f39d05594ca4ad60df5bcb7e32247f9951fd09a9b8edb82d1daa/contourpy-1.3.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:3d1a3799d62d45c18bafd41c5fa05120b96a28079f2393af559b843d1a966a77", size = 225315, upload-time = "2025-07-26T12:02:58.801Z" }, +] + +[[package]] +name = "cycler" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, +] + +[[package]] +name = "dateparser" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, + { name = "pytz" }, + { name = "regex" }, + { name = "tzlocal" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/46/2d/a0ccdb78788064fa0dc901b8524e50615c42be1d78b78d646d0b28d09180/dateparser-1.4.0.tar.gz", hash = "sha256:97a21840d5ecdf7630c584f673338a5afac5dfe84f647baf4d7e8df98f9354a4", size = 321512, upload-time = "2026-03-26T09:56:10.292Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b4/0b/3c3bb7cbe757279e693a0be6049048012f794d01f81099609ecd53b899f0/dateparser-1.4.0-py3-none-any.whl", hash = "sha256:7902b8e85d603494bf70a5a0b1decdddb2270b9c6e6b2bc8a57b93476c0df378", size = 300379, upload-time = "2026-03-26T09:56:08.409Z" }, +] + +[[package]] +name = "decorator" +version = "5.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/60/8b/32f9823da46cde7df2087faa08cd98d01b908f8dcab982cdba9c84e85355/decorator-5.3.1.tar.gz", hash = "sha256:4cbcdd55a6efadb9dbea26b858f4fb3264567b52d69ca0d25b721b553f60ea82", size = 58084, upload-time = "2026-05-18T06:03:28.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/7f/798705f5296a58ca505d600456748d1be48078eac8a7050d8a98bc9edb89/decorator-5.3.1-py3-none-any.whl", hash = "sha256:f47fe6fdbd2edd623ecfe36875d37aba411624e2670dd395dddae1358689bb3c", size = 10365, upload-time = "2026-05-18T06:03:26.517Z" }, +] + +[[package]] +name = "dill" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/81/e1/56027a71e31b02ddc53c7d65b01e68edf64dea2932122fe7746a516f75d5/dill-0.4.1.tar.gz", hash = "sha256:423092df4182177d4d8ba8290c8a5b640c66ab35ec7da59ccfa00f6fa3eea5fa", size = 187315, upload-time = "2026-01-19T02:36:56.85Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl", hash = "sha256:1e1ce33e978ae97fcfcff5638477032b801c46c7c65cf717f95fbc2248f79a9d", size = 120019, upload-time = "2026-01-19T02:36:55.663Z" }, +] + +[[package]] +name = "distro" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722, upload-time = "2023-12-24T09:54:32.31Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, +] + +[[package]] +name = "duckdb" +version = "1.5.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/69/00/d579dcb2a536b6ea3a2563cdad6844f77d81a9b2d4b22a858097f2468acf/duckdb-1.5.3.tar.gz", hash = "sha256:df39428eb130faa35ae96fd35245bdeae6ecf43936250b116b5fead568eb9f16", size = 18026640, upload-time = "2026-05-20T11:55:31.901Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/fc/a8a89c6c73f31c2b58c6abbc2f543e0b736042dd5ef7cc1784c24ec31428/duckdb-1.5.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:341a2672e2551ba51c95c1898f0ade983e76675e79038ccb16342c3d6cfb82d7", size = 32583465, upload-time = "2026-05-20T11:54:13.132Z" }, + { url = "https://files.pythonhosted.org/packages/63/f1/3423a2f523dd034e505d4a5dd8e210ae577212e152598dc13b6a5e736e1b/duckdb-1.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c9e8fa408705081160ede7ead238d16e73a36b8561b700f2bf2d650ae48e7b92", size = 17278520, upload-time = "2026-05-20T11:54:16.368Z" }, + { url = "https://files.pythonhosted.org/packages/e1/1a/7bf5ba1b7ea520557e6b2dbee1c85abab016bdac0c1779d9d0ef76c87300/duckdb-1.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:70a18f932cf6d87bd0e554613657a515c1443a1724aacfc7ec5137dd28698b03", size = 15424794, upload-time = "2026-05-20T11:54:19.891Z" }, + { url = "https://files.pythonhosted.org/packages/ad/16/ce4b1e386e45fab0268edbf1b85bace20e9437589e9edb2bd5f9a226fa44/duckdb-1.5.3-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e80eb4d0fb59869cb2c7d7ef494c07fb92014fe8e77d96c170cd1ebc1488a708", size = 19306666, upload-time = "2026-05-20T11:54:22.77Z" }, + { url = "https://files.pythonhosted.org/packages/99/1f/651f8453f26931e8061b7e27b3090f868868185814ecb9216d0bd71ec8ef/duckdb-1.5.3-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3248b49cd835ea322574bc6aac0ae7a83be85547f49d4f5f5777cb380ee6627f", size = 21418306, upload-time = "2026-05-20T11:54:25.616Z" }, + { url = "https://files.pythonhosted.org/packages/bc/64/e1ffebf010b1631a6fef8d1508f46d4eab3e97c18729af986bb796fa8452/duckdb-1.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:f4eff89c12c3a362efa012262e57b7b4ab904a7f79bad9178fe365510077abe8", size = 13101423, upload-time = "2026-05-20T11:54:28.107Z" }, + { url = "https://files.pythonhosted.org/packages/e7/42/b1d4e34f9658cc0e13d7aae581ab82643f50a548d5aee8767f0c587cc3a4/duckdb-1.5.3-cp311-cp311-win_arm64.whl", hash = "sha256:75d13308c9da3ee431d1e72b8ab720aa74a1b3e9159d4124cb62435924496334", size = 13951740, upload-time = "2026-05-20T11:54:30.886Z" }, + { url = "https://files.pythonhosted.org/packages/e7/c4/2e34929b16c8d544ef664fad8f7f3a2a9db05746aae1e7c8c4ee3a8b23e4/duckdb-1.5.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ff11a457258148337ef9a392148a8cdbd1069b6c27c21958816c7b67fe6c542d", size = 32626494, upload-time = "2026-05-20T11:54:33.738Z" }, + { url = "https://files.pythonhosted.org/packages/3a/53/3af681793d03771365ae3e2215331151c196a3ac8193f613344840694671/duckdb-1.5.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5fd25f533cb1b6b2c84cc767a9a9bab7769bb1aa44571a2a0bfc91ac3e4a38ac", size = 17301121, upload-time = "2026-05-20T11:54:36.928Z" }, + { url = "https://files.pythonhosted.org/packages/15/e2/c80af1eac2ab5d35fc2c372ef0a84668842e549fbbf7799277b3fccf3e39/duckdb-1.5.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:10960400ed60cdf0fe05bab2086fa8eb733889cb0ceca18d07ff9a00c0e0be7b", size = 15449283, upload-time = "2026-05-20T11:54:39.777Z" }, + { url = "https://files.pythonhosted.org/packages/2d/9a/c63af233c9f761bf5178a5210437e1bc6bcb30fa8a9073de6398cfb12c03/duckdb-1.5.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c5f18e7561403054433706c187589e86629a7af09a7efc23a06a8b308e6acc68", size = 19332762, upload-time = "2026-05-20T11:54:42.51Z" }, + { url = "https://files.pythonhosted.org/packages/21/cc/2d77af4fff86012f334ef82e6d54a995a86c8745e58074f1218ed7d25171/duckdb-1.5.3-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9fb7516255a8764545e30f7efacea408cc847764a3027b3b0b3e7d1a7bebbc5c", size = 21453290, upload-time = "2026-05-20T11:54:45.272Z" }, + { url = "https://files.pythonhosted.org/packages/8d/5e/9bc4817a98feb4dab83e56f2245cd3a30d00ee646d4dec7926464e2b3f28/duckdb-1.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:8001eccbc28be244dfd04d708526f34ddd6460b47a8aeb5d0e39d6f7f9e3fe15", size = 13118308, upload-time = "2026-05-20T11:54:48.058Z" }, + { url = "https://files.pythonhosted.org/packages/81/35/e3f32e4e53e2450ddb1db8312a17d1ce455d60cc4941b6ad2cfc908794b0/duckdb-1.5.3-cp312-cp312-win_arm64.whl", hash = "sha256:6d2835e39bb6af73891f73c0f8d4324f98afe00d0b00c6d34b2a582c2256cbb0", size = 13927187, upload-time = "2026-05-20T11:54:50.584Z" }, + { url = "https://files.pythonhosted.org/packages/cc/9c/a528eb09d8be51954c485864bd06753e616939a080cbc3dd4417e8c94a57/duckdb-1.5.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e75a6122c12579a99848517f6f00a4e342aebda3590c30fe9b5cc5f39d5e6afc", size = 32626254, upload-time = "2026-05-20T11:54:53.65Z" }, + { url = "https://files.pythonhosted.org/packages/ec/3c/1534c0a6db347c05eb7d0f6ecfb7aefbe74cbff398e4892a8fd1903a20e8/duckdb-1.5.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fd3963c1cb9d9567777f4a898a9dbe388a2fe9724681801b1e7d6d93eecf1b76", size = 17300917, upload-time = "2026-05-20T11:54:56.628Z" }, + { url = "https://files.pythonhosted.org/packages/23/fa/beafb91e6e152d2161c4a9cbc472334c87607eb61ad7104b5a7fa8d8d7b1/duckdb-1.5.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3d5db8c0b55e072cf437948ebb5d7e23d7b9d03d905fa5f9145583e65aa447f7", size = 15449411, upload-time = "2026-05-20T11:54:59.089Z" }, + { url = "https://files.pythonhosted.org/packages/50/0a/49b6fe04e2fcd63729eb607dadd44818dde77342a4f5ce086c6c92f1dd4d/duckdb-1.5.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ce80aed7a538422129a57eaca9141e3afb51f8bf562b1908b1576c9725b5b22", size = 19333120, upload-time = "2026-05-20T11:55:01.727Z" }, + { url = "https://files.pythonhosted.org/packages/63/4c/0907c3f76adb9dd90e67610b31e0304a35814e65c4c41a354a262c09b885/duckdb-1.5.3-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:787df63824f07bf18022dbc3b8ca4b2bfab0ebe616464f55c6e8cd0f59ea762e", size = 21453266, upload-time = "2026-05-20T11:55:04.5Z" }, + { url = "https://files.pythonhosted.org/packages/6d/9c/d2f23a7803ddbbd9413f7572ecf66a15120ed5ced7ce5c73e698c1406b76/duckdb-1.5.3-cp313-cp313-win_amd64.whl", hash = "sha256:bb5bb5dcdd09d62ee60f0ddbbef918e71cce304ffe28428b1131949d39ffaabf", size = 13118640, upload-time = "2026-05-20T11:55:07.389Z" }, + { url = "https://files.pythonhosted.org/packages/27/d5/7ba2316415bcdab6edd765bbbe35c2ca8a3800f2fe695cd70e3cdb997f09/duckdb-1.5.3-cp313-cp313-win_arm64.whl", hash = "sha256:2fa17ecdd5d3db122836cb71bb93601c2106a3be883c17dffddc02fbf3fa7888", size = 13926409, upload-time = "2026-05-20T11:55:10.166Z" }, + { url = "https://files.pythonhosted.org/packages/a5/c2/d4b6f8a5e4d3bc25773be6da76a99d9661ebbf3552c007c460d2dd59dbf8/duckdb-1.5.3-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:4bfa9a4dadf71e83e2c4eaca2f9421c82a54defecc1b0b4c0be95e2389dec4fe", size = 32636685, upload-time = "2026-05-20T11:55:13.158Z" }, + { url = "https://files.pythonhosted.org/packages/42/58/e835c8298979d29db7a62cb5acc29e9b57aeaca7cdde2fcd3ac980f5cb18/duckdb-1.5.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:aea7baf67ad7e1829ac76f67d7dcbd7fb1f57c3eb179d55ac30952df4709ae30", size = 17308134, upload-time = "2026-05-20T11:55:16.194Z" }, + { url = "https://files.pythonhosted.org/packages/c9/46/617b51363f5613418c8b224b3cce16b58e6dde80904566bec232579c1d4e/duckdb-1.5.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b0b4f088a65d77e1217ce5d7eff889e63fedc44281200d899ff47c84d8ff836", size = 15449891, upload-time = "2026-05-20T11:55:18.687Z" }, + { url = "https://files.pythonhosted.org/packages/b3/72/354146656e8d9ba3853d3a5ee80a481b8c5f70edfc3d5ae80a8c4479c967/duckdb-1.5.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fe8d0c1f6a120aa03fa6e0d03897c71a1842e6cf7afd31d181348391f7108fe1", size = 19338499, upload-time = "2026-05-20T11:55:21.34Z" }, + { url = "https://files.pythonhosted.org/packages/56/8f/65fc623b51448f2bfba1a9ec6ab3debb4664c0876c0113a5e782600b53ac/duckdb-1.5.3-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0405eae18ec6e8210a471c97dbfe87a7e4d605274b7fe572a1f276e92158f13", size = 21455828, upload-time = "2026-05-20T11:55:23.847Z" }, + { url = "https://files.pythonhosted.org/packages/2b/db/d0274cbe9f5fe219f77c0bdf900ac77103569e83c102a4225ce04cbc607d/duckdb-1.5.3-cp314-cp314-win_amd64.whl", hash = "sha256:33ae08b3e818d7613d8936744b67718c2062c2f530376895bfd89efb51b81538", size = 13640011, upload-time = "2026-05-20T11:55:26.276Z" }, + { url = "https://files.pythonhosted.org/packages/07/5d/8f1899b8bef291caf953992fcd6c24df9f29387a35645e58c2504a5ca473/duckdb-1.5.3-cp314-cp314-win_arm64.whl", hash = "sha256:746433e49bbc667b4df283153415fbe37e9083e0eff6c3cd6e54de7536869cd4", size = 14411554, upload-time = "2026-05-20T11:55:29.037Z" }, +] + +[[package]] +name = "executing" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, +] + +[[package]] +name = "fastapi" +version = "0.136.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-doc" }, + { name = "pydantic" }, + { name = "starlette" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5d/45/c130091c2dfa061bbfe3150f2a5091ef1adf149f2a8d2ae769ecaf6e99a2/fastapi-0.136.1.tar.gz", hash = "sha256:7af665ad7acfa0a3baf8983d393b6b471b9da10ede59c60045f49fbc89a0fa7f", size = 397448, upload-time = "2026-04-23T16:49:44.046Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/ff/2e4eca3ade2c22fe1dea7043b8ee9dabe47753349eb1b56a202de8af6349/fastapi-0.136.1-py3-none-any.whl", hash = "sha256:a6e9d7eeada96c93a4d69cb03836b44fa34e2854accb7244a1ece36cd4781c3f", size = 117683, upload-time = "2026-04-23T16:49:42.437Z" }, +] + +[[package]] +name = "fastexcel" +version = "0.20.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/96/24314765a3204081a55ecc96e83dfdbd2ef82aa80a521ac3005b2c91e941/fastexcel-0.20.2.tar.gz", hash = "sha256:a4be10eb0f4dd819d2b36950b3f26bf87260b53e54150ac02b78e524c7063902", size = 60862, upload-time = "2026-05-04T12:28:36.01Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/29/29/acc5b2eb95fb4eaeb3486b6f034f2d9754dcc0cc0b5dbc79b2fa9a31f66b/fastexcel-0.20.2-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:2a240b9f4b6af42cafc247c1b8c956cf32f5393a3956ad0ed49e07b2b5bf0e09", size = 3432179, upload-time = "2026-05-04T12:28:24.611Z" }, + { url = "https://files.pythonhosted.org/packages/3f/2b/f78a2df2d93ec4a23d7fc94ed967bf004d5115e1f4d2da389bb888d2cc32/fastexcel-0.20.2-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:6c7e58cf83c873743c18006e3866d5c2b69c34df7a4a253a72e81169853ddf0e", size = 3260476, upload-time = "2026-05-04T12:28:26.191Z" }, + { url = "https://files.pythonhosted.org/packages/36/9c/a8f45e5c195a70a408893b348595bae4c113091dddba7d1b029e9c980b8e/fastexcel-0.20.2-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdab3cc439c18c4ee14c4ec2b321e1d927cae84f557525f390a3c28517f6e721", size = 3625132, upload-time = "2026-05-04T12:28:12.173Z" }, + { url = "https://files.pythonhosted.org/packages/b4/01/da0ae9b3ee86daca5ac9f0a7b05477cf0c1624321d95f1e52492a772dba5/fastexcel-0.20.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15d41bcc4433bb3ab778426ecaeaf3a5f38d949555c631a83e958c57bb0a116e", size = 3789901, upload-time = "2026-05-04T12:28:13.884Z" }, + { url = "https://files.pythonhosted.org/packages/c5/15/80c614c8b07c631c7c2acd015e7f2e1cd683cd04279e5615b39c36a0e43b/fastexcel-0.20.2-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:441f9b7e97b4fd1c9487e5c0a0d9cad7aa4097a39e65fcd494551f5ec3e5d02f", size = 3792388, upload-time = "2026-05-04T12:28:15.448Z" }, + { url = "https://files.pythonhosted.org/packages/c0/80/4548305ce4d70a0ecf38205988e5caeb9347dae7e5d06bcd2b939586fc52/fastexcel-0.20.2-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8b15f21baef3e4914071e34f176d8692dd79e3464c10f8373047aab1384cfaae", size = 3960316, upload-time = "2026-05-04T12:28:16.821Z" }, + { url = "https://files.pythonhosted.org/packages/22/b3/7de6b49406fda63c9fee817d5fc70fe3f52c24431605f1de2f7b0f3a0938/fastexcel-0.20.2-cp310-abi3-win_amd64.whl", hash = "sha256:ce28748390ae6a7d286ba29d8ee2badcfb6478d32ed700db6c2030de32a16e7b", size = 3275637, upload-time = "2026-05-04T12:28:30.45Z" }, + { url = "https://files.pythonhosted.org/packages/d8/3b/c251f38596d630e87280c191f53803e7409e7723e95e53a477f6760c7298/fastexcel-0.20.2-cp310-abi3-win_arm64.whl", hash = "sha256:c3e58f5053bc05b0ee8fa735056cea7af6e1c41c39fc4b2b06cc86c1025d140b", size = 2990952, upload-time = "2026-05-04T12:28:32.434Z" }, + { url = "https://files.pythonhosted.org/packages/37/d3/fcc1ba752415327f0fd5a1b52060e66f1c0bf8b7b90bbba781b91750ce7e/fastexcel-0.20.2-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:e5b677d669cc7c099998ef27d9442b78d7190916d3b40418bda619cdc4ebae2c", size = 3427401, upload-time = "2026-05-04T12:28:27.741Z" }, + { url = "https://files.pythonhosted.org/packages/80/bc/e492c343c096e93e269c157fc11def297430047f1ee09db4f8a39bcdc1a0/fastexcel-0.20.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9692ac135ede4d6fc45b25cc22f1c6bd1eb8750bda14097b7f319450c33d3124", size = 3253915, upload-time = "2026-05-04T12:28:29.053Z" }, + { url = "https://files.pythonhosted.org/packages/dd/ef/bd7b98149b50e01fdaa3b146b025ce50b8e983f35522f8e69bd94d2711a4/fastexcel-0.20.2-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:675d7eab2110bd8d5520b98d5eb3f3e15173b69a5f64b43412f917e9717e9aa0", size = 3621364, upload-time = "2026-05-04T12:28:18.457Z" }, + { url = "https://files.pythonhosted.org/packages/4c/e0/f67911db6515df326900e8ac1ae17cc08233ca5fb8f71c633f57a50cf786/fastexcel-0.20.2-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db049d51e5323459f534ce9a65869f997bebd4dde75ef1d3b3af53dd64b8b9ca", size = 3784924, upload-time = "2026-05-04T12:28:19.955Z" }, + { url = "https://files.pythonhosted.org/packages/34/82/fabe2d1de28e89a90bb2c884c37d862b5d85063fd41fffcb56b2980d0b51/fastexcel-0.20.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e5b23f69898f6a32c2f279d8f72eb8ac93c336bf7f453a9b8930cab9dc494520", size = 3791264, upload-time = "2026-05-04T12:28:21.612Z" }, + { url = "https://files.pythonhosted.org/packages/f7/34/b3ed819dd6d35d71c6640ff857c6362d42f19e8b15354e64b06f355df3a4/fastexcel-0.20.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c3058d034e75967b6f01e0c82767adeb40cbf4533b6bc54e3b93f77f5f80dec4", size = 3953234, upload-time = "2026-05-04T12:28:23.224Z" }, + { url = "https://files.pythonhosted.org/packages/3a/51/1d9a72473cc213d5647d8cf7c2393ef995b3453ac5e4b544ba652d1428dd/fastexcel-0.20.2-cp314-cp314t-win_amd64.whl", hash = "sha256:d71e2a1fce006cb8bc1ae06da6ff5e5fe83e6496be5aef01b623b15aa0d0f82d", size = 3271344, upload-time = "2026-05-04T12:28:34.443Z" }, +] + +[[package]] +name = "fonttools" +version = "4.63.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/84/69/c97f2c18e0db87d2c7b15da1974dace76ae938f1cfa22e2727a648b7ed43/fonttools-4.63.0.tar.gz", hash = "sha256:caeb583deeb5168e694b65cda8b4ee62abedfa66cf88488734466f2366b9c4e0", size = 3597189, upload-time = "2026-05-14T12:04:30.958Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/75/2b/a7f1545bdf5da69c4bda0cea2a5781f0ad2a6623e0277267672db43c5fe6/fonttools-4.63.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2b8ae05d9eacf6081414d759c0a352769ac28ce31280d6bb8e77b03f9e3c449f", size = 2881793, upload-time = "2026-05-14T12:02:56.645Z" }, + { url = "https://files.pythonhosted.org/packages/49/50/965308c703f085f225db2886813b27e015b8b3438c350b22dd65b52c2a2c/fonttools-4.63.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:79cdc9f567aec74a72918fd060283911406750cbc9fd28c1316023deb6ce31a9", size = 2428130, upload-time = "2026-05-14T12:02:58.891Z" }, + { url = "https://files.pythonhosted.org/packages/d8/38/6937fbd7f2dc3a6b48725851bc2c15ec949b9af14d9bbcb5fe83cdf9bdf9/fonttools-4.63.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c14b4fd138c4bafcca294765c547914e1aa431ae1ca94ab99d8db08c958bd3b", size = 5111952, upload-time = "2026-05-14T12:03:01.263Z" }, + { url = "https://files.pythonhosted.org/packages/0b/43/a81f20050a3115b57d62c8e781446949512eac36690dc384ccea65ff4cc1/fonttools-4.63.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d76ac49f929aecaf82d83250b8347e099d7aecba0f4726c1d9b6df3b8bb5fe18", size = 5082308, upload-time = "2026-05-14T12:03:03.211Z" }, + { url = "https://files.pythonhosted.org/packages/67/00/cdd9d4944ca6ae280d01e69cc37bde3bf663630b837a6fc6d2cd65d80e0e/fonttools-4.63.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dcf076a4474fe0d7367e5bbf5b052c7284fa1feca729c04176ce513521afd8a0", size = 5087932, upload-time = "2026-05-14T12:03:05.147Z" }, + { url = "https://files.pythonhosted.org/packages/f5/f1/0aa0dbea778c75adbef223c42019fd47d22262b905974d62d829545d485f/fonttools-4.63.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7dd683fef0663e9f0f45cf541d788d24caa3ec9db50796b588e1757d8b3bc007", size = 5213271, upload-time = "2026-05-14T12:03:07.238Z" }, + { url = "https://files.pythonhosted.org/packages/a8/99/253e4056e1f0e67b9390125a154b73b5eb73ad521bece95c004858fdeec2/fonttools-4.63.0-cp311-cp311-win32.whl", hash = "sha256:afefc1ed0a59785a7fb06ea7e1678e849c193e1e387db783579bc7b3056fcfcb", size = 2304473, upload-time = "2026-05-14T12:03:09.271Z" }, + { url = "https://files.pythonhosted.org/packages/08/60/defa5e69641db890a63be281f41345f4c33b157824eaf0b9fad3e08b0dcb/fonttools-4.63.0-cp311-cp311-win_amd64.whl", hash = "sha256:063e08bd17bd5a90127a14123de0d6a952dbc847695fd98b63c043d58057f90c", size = 2356389, upload-time = "2026-05-14T12:03:11.53Z" }, + { url = "https://files.pythonhosted.org/packages/08/ef/b3c6b9b5be2f82416d73fe2ed2e96e2793cd80e7510bd6a17ca79cdd88ec/fonttools-4.63.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:37dd23e621e3b0aef1baa70a303b80aaf38449632cfc8fd2a55fb285bbccfc02", size = 2881131, upload-time = "2026-05-14T12:03:13.386Z" }, + { url = "https://files.pythonhosted.org/packages/44/a0/c815bea63117fa63e4e1c01f8a1110d2112fa003f838e6467094ec2432ce/fonttools-4.63.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a9faff9e0c1f76f9fd55899d2ce785832efebab37eb8ae13995853aef178bef0", size = 2426704, upload-time = "2026-05-14T12:03:15.801Z" }, + { url = "https://files.pythonhosted.org/packages/44/04/0b91d8e916e92ad1fac9e4624760baf0fd5ff2ead614c2f68fb21373f03f/fonttools-4.63.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef3048ef05dbb552b89817713d9cac912e00d0fde4a3105c00d29e52e10c89af", size = 5044298, upload-time = "2026-05-14T12:03:18.085Z" }, + { url = "https://files.pythonhosted.org/packages/77/c7/2342da9830e3e9d4870305ca5d2091d2a83284f2953079b7bdd3b5e029d8/fonttools-4.63.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:58dc6bb86a78d782f00f9190ca02c119cf5bbe2807536e361e18d42019f877d8", size = 4999800, upload-time = "2026-05-14T12:03:20.161Z" }, + { url = "https://files.pythonhosted.org/packages/e6/6d/67fe16c48d7ce050979b33f47e0d28a318f02da030602e944c34f7a16ef3/fonttools-4.63.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ee08ebfa58f6e1aeff5697ab9582105bb620008c1caafb681e4c557e7483027b", size = 4982666, upload-time = "2026-05-14T12:03:22.87Z" }, + { url = "https://files.pythonhosted.org/packages/f2/00/3bbab338c07c71fa56269953845e92c951a61457bbbb0f1022551ea266d9/fonttools-4.63.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:27fdc65af8da6f88b9c6121c47a464cbe359fcfff7ff6fc2d37a1f395d755b78", size = 5133598, upload-time = "2026-05-14T12:03:25.168Z" }, + { url = "https://files.pythonhosted.org/packages/62/f2/aa27c7f98db5b064883dadcc5283947e81e034de42e22a33675878d98b54/fonttools-4.63.0-cp312-cp312-win32.whl", hash = "sha256:af2fd1664d00a397d75f806985ddb36282091c2131a73a6485c23b4a34722263", size = 2292575, upload-time = "2026-05-14T12:03:27.496Z" }, + { url = "https://files.pythonhosted.org/packages/87/36/cccb9bc2a6ab63d1b2980374f0dca72ce95ae267c9b4cfe77455bb70d0d4/fonttools-4.63.0-cp312-cp312-win_amd64.whl", hash = "sha256:59ac449f8cca9b4ffa08d2e7bbadad87ce710d69d1eda5c3c1ce579baa987272", size = 2343211, upload-time = "2026-05-14T12:03:30.057Z" }, + { url = "https://files.pythonhosted.org/packages/0f/8d/d8fec3dcde2963f8c908fb315e5ff2cd0ac34f82394bbbf73a2aa5145ce3/fonttools-4.63.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:cd7e9857e5e63738b9d9fd707bc1f59c8b09e5177726d23664db393c59bb08bd", size = 2876062, upload-time = "2026-05-14T12:03:32.554Z" }, + { url = "https://files.pythonhosted.org/packages/ef/71/d935dc54e4ff121bfdd11e08702db63a7e6f25af21d8a3d7b7212df53641/fonttools-4.63.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c2a2a42198b696a6f48fad91709afb55176e66a5e566131219dba372fb7f8c59", size = 2424594, upload-time = "2026-05-14T12:03:34.86Z" }, + { url = "https://files.pythonhosted.org/packages/8e/40/e76320afa1df918e146155ef239b1719ee266092e96f5423bfd075affba1/fonttools-4.63.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e874792a8212b44583ea02189d9e693906b2f78b261f372f95d6c563210ac1d", size = 5024840, upload-time = "2026-05-14T12:03:36.745Z" }, + { url = "https://files.pythonhosted.org/packages/ce/36/0b805d8c485f872f65a509cbe3b58a5d0d17bee855333b54a150c79d3061/fonttools-4.63.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22135da48a348785c5e2d5d2d9d6bec5ed44adacbaeb9db12d9493bf6c6bfa68", size = 4975801, upload-time = "2026-05-14T12:03:38.833Z" }, + { url = "https://files.pythonhosted.org/packages/c8/26/2cee03d0aa083ab022da5c07aff9ed3f689da1defb81ad6917c9627896da/fonttools-4.63.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ccf41f2efdf56994d22d73bef4ced1052161958169428d06ba9724ea9e9a64be", size = 4965009, upload-time = "2026-05-14T12:03:41.494Z" }, + { url = "https://files.pythonhosted.org/packages/7e/48/cc4b66d9058c0d0982c833fad10127c4b0e9324606aafa41382295ca4102/fonttools-4.63.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9ced0bd02ac751dd6319b0da88aaef24414e3b0dbc32bb4f24944821a3741a27", size = 5105892, upload-time = "2026-05-14T12:03:43.525Z" }, + { url = "https://files.pythonhosted.org/packages/d8/1f/a98a30a814b9ddef3a2e706025f90b9e0bc94890e6cb15254bc86547d11a/fonttools-4.63.0-cp313-cp313-win32.whl", hash = "sha256:85be818f5506e8a7753153def2c9550178f0ecae6a47b5e0e8dbb23f7cc90380", size = 2291313, upload-time = "2026-05-14T12:03:45.594Z" }, + { url = "https://files.pythonhosted.org/packages/92/46/5177b01f3b4abfdd4409f31cca4ab279c9343a26efbe9ec78c97fc612e02/fonttools-4.63.0-cp313-cp313-win_amd64.whl", hash = "sha256:ba04cb5891d4c0c21b6da95eda8d7b090021508a294fff33464fc7d241e0856b", size = 2342299, upload-time = "2026-05-14T12:03:47.414Z" }, + { url = "https://files.pythonhosted.org/packages/27/d2/23d25e3f247b328be58d04a4c9f894178a0d1eda7d42867cfb388adaf416/fonttools-4.63.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fd1e3094f42d806d3d7c79162fc59e5910fcbe3a7360c385b8da969bc4493745", size = 2875338, upload-time = "2026-05-14T12:03:50.052Z" }, + { url = "https://files.pythonhosted.org/packages/cd/58/7dfa0c761cb3b2964e2a84c4dc986c926a87de0cb9fb60d5b28ded3f2914/fonttools-4.63.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:6e528da43bc3791085f8cb6141b1d13e459226790240340fcbb4625649238b03", size = 2422661, upload-time = "2026-05-14T12:03:52.154Z" }, + { url = "https://files.pythonhosted.org/packages/dd/87/64cfa18a7a1621d17b7f4502b2b0ed8a135a90c3db51ea590ee99043e76b/fonttools-4.63.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b2248c5decb223562f7902ff6325077a073f608ee8e33e88ad88db734eb9f49", size = 5010526, upload-time = "2026-05-14T12:03:54.647Z" }, + { url = "https://files.pythonhosted.org/packages/36/e1/a8933a72c45a87177fbde2696e0d0755c8c9062f8c077a961c6215fa27b1/fonttools-4.63.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:308f957cdeaf8abe4e5f2f124902ef405448af92c90f80e302a3b771c2e6116b", size = 4923946, upload-time = "2026-05-14T12:03:56.984Z" }, + { url = "https://files.pythonhosted.org/packages/27/60/872e6e233b8c5e8b41413796ff18b7fe479661bd40147e071b450dfad7a1/fonttools-4.63.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bf00f21eb5fb721dbaf73d1e9da6d02a1af7768f2ebcf9798be98beab8ba90f6", size = 4962489, upload-time = "2026-05-14T12:03:59.443Z" }, + { url = "https://files.pythonhosted.org/packages/30/c4/83c24f2ec38b90cfda84bf4b1a1f49df80e84a1db4e7ac6e0d41bf23bc39/fonttools-4.63.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c1aaa4b9c75798400ac043ce04d74e7830376c85095a5a6ed7cba2f17a266bf4", size = 5071870, upload-time = "2026-05-14T12:04:02.122Z" }, + { url = "https://files.pythonhosted.org/packages/de/40/3ae22b60ff1d41ce0bd044b31238cdc72cef99f28b976f1e128ebd618c9b/fonttools-4.63.0-cp314-cp314-win32.whl", hash = "sha256:22693918177bd9ceabec4736d338045f357769416fc6b0b2508eefef75b08616", size = 2295026, upload-time = "2026-05-14T12:04:04.47Z" }, + { url = "https://files.pythonhosted.org/packages/c3/d4/98078064ccc76b45cb0f6c002452011e93c4bd26f6850344f0951cc1fe89/fonttools-4.63.0-cp314-cp314-win_amd64.whl", hash = "sha256:7d782fac32985914c351556f68ac0855391572bcd87de50e05970d3cd4c96fc5", size = 2347454, upload-time = "2026-05-14T12:04:06.752Z" }, + { url = "https://files.pythonhosted.org/packages/49/4e/652d1580c5f4e39f7d103b0c793e4773129ad633dce4addd0cf4dfebde02/fonttools-4.63.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:6db5140a60a5d731d21ec076745b40a310607731b0a565b50776393188649001", size = 2958152, upload-time = "2026-05-14T12:04:08.706Z" }, + { url = "https://files.pythonhosted.org/packages/0e/55/ad864c9a9b219f552eb46b32cd7906c466e5a578ba0c3abfcc0fe7413eb6/fonttools-4.63.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:7d76edbff9014094dbf03bd2d074709dfa6ec7aba13d838c937a2b33d2d6a86e", size = 2460809, upload-time = "2026-05-14T12:04:10.783Z" }, + { url = "https://files.pythonhosted.org/packages/ea/2b/0aa8db70f18cf52e49b4ed5ecec68547f981160bf5ded3b5aed6faa0a6f9/fonttools-4.63.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0eac00b9118c3c2f87d272e45341871c5b3066baa3c86897fa634a7c3fb59096", size = 5148649, upload-time = "2026-05-14T12:04:12.747Z" }, + { url = "https://files.pythonhosted.org/packages/7f/63/18e4369c25043096f1048e0c9915951adc4f842bd81c6b18155824d6fa99/fonttools-4.63.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:51394295f1a51de8b5f30bdb1e1b9a4231536c7064ef5c6e211eec19fa36036f", size = 4932147, upload-time = "2026-05-14T12:04:14.806Z" }, + { url = "https://files.pythonhosted.org/packages/a1/3f/67f3eac2ffd8a98446c5022f8ed3864eac878a5ff7af8df4c8286dba16cc/fonttools-4.63.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9e12f105d2b6342c559c298afb674006bb2893afc7102dcf8a1b55b0486b4e40", size = 5027237, upload-time = "2026-05-14T12:04:17.675Z" }, + { url = "https://files.pythonhosted.org/packages/1a/ba/4e6214cb38a7b04779e97bb7636de9a5c7f20af7018d03dee0b64c08510a/fonttools-4.63.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:796f27556dbe094c4824f75ca85267e4df776c79036c8441469a4df37038c196", size = 5053933, upload-time = "2026-05-14T12:04:20.818Z" }, + { url = "https://files.pythonhosted.org/packages/34/3b/214dcc19ee31d3d38fb5ad2755c11ef0514e5dc300bbaf41c0b69f393799/fonttools-4.63.0-cp314-cp314t-win32.whl", hash = "sha256:948428a275741f0b64b113c955425a953314f4b9ab9997f73a72c83e68e569c8", size = 2359326, upload-time = "2026-05-14T12:04:24.22Z" }, + { url = "https://files.pythonhosted.org/packages/dd/1e/3ff1a9b523058c2eeb6a9d50f5574e2a738200d0d94107d5bc4105e8da3f/fonttools-4.63.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6d4741eb179121cab9eea4cb2393d24492373a260d7945006358c08cfbf45419", size = 2425829, upload-time = "2026-05-14T12:04:26.829Z" }, + { url = "https://files.pythonhosted.org/packages/2c/47/c99d5268f354002ce80f8d029cd9d7d872969da1de8b93d32de4dc56d6f4/fonttools-4.63.0-py3-none-any.whl", hash = "sha256:445af2eab030a16b9171ea8bdda7ebf7d96bda2df88ee182a464252f6e05e20d", size = 1164562, upload-time = "2026-05-14T12:04:29.092Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httptools" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/46/120a669232c7bdedb9d52d4aeae7e6c7dfe151e99dc70802e2fc7a5e1993/httptools-0.7.1.tar.gz", hash = "sha256:abd72556974f8e7c74a259655924a717a2365b236c882c3f6f8a45fe94703ac9", size = 258961, upload-time = "2025-10-10T03:55:08.559Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/08/17e07e8d89ab8f343c134616d72eebfe03798835058e2ab579dcc8353c06/httptools-0.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:474d3b7ab469fefcca3697a10d11a32ee2b9573250206ba1e50d5980910da657", size = 206521, upload-time = "2025-10-10T03:54:31.002Z" }, + { url = "https://files.pythonhosted.org/packages/aa/06/c9c1b41ff52f16aee526fd10fbda99fa4787938aa776858ddc4a1ea825ec/httptools-0.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3c3b7366bb6c7b96bd72d0dbe7f7d5eead261361f013be5f6d9590465ea1c70", size = 110375, upload-time = "2025-10-10T03:54:31.941Z" }, + { url = "https://files.pythonhosted.org/packages/cc/cc/10935db22fda0ee34c76f047590ca0a8bd9de531406a3ccb10a90e12ea21/httptools-0.7.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:379b479408b8747f47f3b253326183d7c009a3936518cdb70db58cffd369d9df", size = 456621, upload-time = "2025-10-10T03:54:33.176Z" }, + { url = "https://files.pythonhosted.org/packages/0e/84/875382b10d271b0c11aa5d414b44f92f8dd53e9b658aec338a79164fa548/httptools-0.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cad6b591a682dcc6cf1397c3900527f9affef1e55a06c4547264796bbd17cf5e", size = 454954, upload-time = "2025-10-10T03:54:34.226Z" }, + { url = "https://files.pythonhosted.org/packages/30/e1/44f89b280f7e46c0b1b2ccee5737d46b3bb13136383958f20b580a821ca0/httptools-0.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:eb844698d11433d2139bbeeb56499102143beb582bd6c194e3ba69c22f25c274", size = 440175, upload-time = "2025-10-10T03:54:35.942Z" }, + { url = "https://files.pythonhosted.org/packages/6f/7e/b9287763159e700e335028bc1824359dc736fa9b829dacedace91a39b37e/httptools-0.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f65744d7a8bdb4bda5e1fa23e4ba16832860606fcc09d674d56e425e991539ec", size = 440310, upload-time = "2025-10-10T03:54:37.1Z" }, + { url = "https://files.pythonhosted.org/packages/b3/07/5b614f592868e07f5c94b1f301b5e14a21df4e8076215a3bccb830a687d8/httptools-0.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:135fbe974b3718eada677229312e97f3b31f8a9c8ffa3ae6f565bf808d5b6bcb", size = 86875, upload-time = "2025-10-10T03:54:38.421Z" }, + { url = "https://files.pythonhosted.org/packages/53/7f/403e5d787dc4942316e515e949b0c8a013d84078a915910e9f391ba9b3ed/httptools-0.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:38e0c83a2ea9746ebbd643bdfb521b9aa4a91703e2cd705c20443405d2fd16a5", size = 206280, upload-time = "2025-10-10T03:54:39.274Z" }, + { url = "https://files.pythonhosted.org/packages/2a/0d/7f3fd28e2ce311ccc998c388dd1c53b18120fda3b70ebb022b135dc9839b/httptools-0.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f25bbaf1235e27704f1a7b86cd3304eabc04f569c828101d94a0e605ef7205a5", size = 110004, upload-time = "2025-10-10T03:54:40.403Z" }, + { url = "https://files.pythonhosted.org/packages/84/a6/b3965e1e146ef5762870bbe76117876ceba51a201e18cc31f5703e454596/httptools-0.7.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2c15f37ef679ab9ecc06bfc4e6e8628c32a8e4b305459de7cf6785acd57e4d03", size = 517655, upload-time = "2025-10-10T03:54:41.347Z" }, + { url = "https://files.pythonhosted.org/packages/11/7d/71fee6f1844e6fa378f2eddde6c3e41ce3a1fb4b2d81118dd544e3441ec0/httptools-0.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7fe6e96090df46b36ccfaf746f03034e5ab723162bc51b0a4cf58305324036f2", size = 511440, upload-time = "2025-10-10T03:54:42.452Z" }, + { url = "https://files.pythonhosted.org/packages/22/a5/079d216712a4f3ffa24af4a0381b108aa9c45b7a5cc6eb141f81726b1823/httptools-0.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f72fdbae2dbc6e68b8239defb48e6a5937b12218e6ffc2c7846cc37befa84362", size = 495186, upload-time = "2025-10-10T03:54:43.937Z" }, + { url = "https://files.pythonhosted.org/packages/e9/9e/025ad7b65278745dee3bd0ebf9314934c4592560878308a6121f7f812084/httptools-0.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e99c7b90a29fd82fea9ef57943d501a16f3404d7b9ee81799d41639bdaae412c", size = 499192, upload-time = "2025-10-10T03:54:45.003Z" }, + { url = "https://files.pythonhosted.org/packages/6d/de/40a8f202b987d43afc4d54689600ff03ce65680ede2f31df348d7f368b8f/httptools-0.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:3e14f530fefa7499334a79b0cf7e7cd2992870eb893526fb097d51b4f2d0f321", size = 86694, upload-time = "2025-10-10T03:54:45.923Z" }, + { url = "https://files.pythonhosted.org/packages/09/8f/c77b1fcbfd262d422f12da02feb0d218fa228d52485b77b953832105bb90/httptools-0.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6babce6cfa2a99545c60bfef8bee0cc0545413cb0018f617c8059a30ad985de3", size = 202889, upload-time = "2025-10-10T03:54:47.089Z" }, + { url = "https://files.pythonhosted.org/packages/0a/1a/22887f53602feaa066354867bc49a68fc295c2293433177ee90870a7d517/httptools-0.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:601b7628de7504077dd3dcb3791c6b8694bbd967148a6d1f01806509254fb1ca", size = 108180, upload-time = "2025-10-10T03:54:48.052Z" }, + { url = "https://files.pythonhosted.org/packages/32/6a/6aaa91937f0010d288d3d124ca2946d48d60c3a5ee7ca62afe870e3ea011/httptools-0.7.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:04c6c0e6c5fb0739c5b8a9eb046d298650a0ff38cf42537fc372b28dc7e4472c", size = 478596, upload-time = "2025-10-10T03:54:48.919Z" }, + { url = "https://files.pythonhosted.org/packages/6d/70/023d7ce117993107be88d2cbca566a7c1323ccbaf0af7eabf2064fe356f6/httptools-0.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:69d4f9705c405ae3ee83d6a12283dc9feba8cc6aaec671b412917e644ab4fa66", size = 473268, upload-time = "2025-10-10T03:54:49.993Z" }, + { url = "https://files.pythonhosted.org/packages/32/4d/9dd616c38da088e3f436e9a616e1d0cc66544b8cdac405cc4e81c8679fc7/httptools-0.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:44c8f4347d4b31269c8a9205d8a5ee2df5322b09bbbd30f8f862185bb6b05346", size = 455517, upload-time = "2025-10-10T03:54:51.066Z" }, + { url = "https://files.pythonhosted.org/packages/1d/3a/a6c595c310b7df958e739aae88724e24f9246a514d909547778d776799be/httptools-0.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:465275d76db4d554918aba40bf1cbebe324670f3dfc979eaffaa5d108e2ed650", size = 458337, upload-time = "2025-10-10T03:54:52.196Z" }, + { url = "https://files.pythonhosted.org/packages/fd/82/88e8d6d2c51edc1cc391b6e044c6c435b6aebe97b1abc33db1b0b24cd582/httptools-0.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:322d00c2068d125bd570f7bf78b2d367dad02b919d8581d7476d8b75b294e3e6", size = 85743, upload-time = "2025-10-10T03:54:53.448Z" }, + { url = "https://files.pythonhosted.org/packages/34/50/9d095fcbb6de2d523e027a2f304d4551855c2f46e0b82befd718b8b20056/httptools-0.7.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:c08fe65728b8d70b6923ce31e3956f859d5e1e8548e6f22ec520a962c6757270", size = 203619, upload-time = "2025-10-10T03:54:54.321Z" }, + { url = "https://files.pythonhosted.org/packages/07/f0/89720dc5139ae54b03f861b5e2c55a37dba9a5da7d51e1e824a1f343627f/httptools-0.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7aea2e3c3953521c3c51106ee11487a910d45586e351202474d45472db7d72d3", size = 108714, upload-time = "2025-10-10T03:54:55.163Z" }, + { url = "https://files.pythonhosted.org/packages/b3/cb/eea88506f191fb552c11787c23f9a405f4c7b0c5799bf73f2249cd4f5228/httptools-0.7.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0e68b8582f4ea9166be62926077a3334064d422cf08ab87d8b74664f8e9058e1", size = 472909, upload-time = "2025-10-10T03:54:56.056Z" }, + { url = "https://files.pythonhosted.org/packages/e0/4a/a548bdfae6369c0d078bab5769f7b66f17f1bfaa6fa28f81d6be6959066b/httptools-0.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df091cf961a3be783d6aebae963cc9b71e00d57fa6f149025075217bc6a55a7b", size = 470831, upload-time = "2025-10-10T03:54:57.219Z" }, + { url = "https://files.pythonhosted.org/packages/4d/31/14df99e1c43bd132eec921c2e7e11cda7852f65619bc0fc5bdc2d0cb126c/httptools-0.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f084813239e1eb403ddacd06a30de3d3e09a9b76e7894dcda2b22f8a726e9c60", size = 452631, upload-time = "2025-10-10T03:54:58.219Z" }, + { url = "https://files.pythonhosted.org/packages/22/d2/b7e131f7be8d854d48cb6d048113c30f9a46dca0c9a8b08fcb3fcd588cdc/httptools-0.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7347714368fb2b335e9063bc2b96f2f87a9ceffcd9758ac295f8bbcd3ffbc0ca", size = 452910, upload-time = "2025-10-10T03:54:59.366Z" }, + { url = "https://files.pythonhosted.org/packages/53/cf/878f3b91e4e6e011eff6d1fa9ca39f7eb17d19c9d7971b04873734112f30/httptools-0.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:cfabda2a5bb85aa2a904ce06d974a3f30fb36cc63d7feaddec05d2050acede96", size = 88205, upload-time = "2025-10-10T03:55:00.389Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "idna" +version = "3.16" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1a/88/bcf9709822fe69d02c2a6a77956c98ce6ea8ca8767a9aadcedc7eb6a2390/idna-3.16.tar.gz", hash = "sha256:d7a6da03db833450fca25d2358ac9ff06cd624577a4aea3a596d5c0f77b8e03d", size = 203770, upload-time = "2026-05-22T00:16:18.781Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/16/70255075a9859a0e3adb789b68ceb0e210dec03934245fd98d248226572f/idna-3.16-py3-none-any.whl", hash = "sha256:cc246e3a3f89580c3a951b5ad298ca4638078b2cdd4f115654332b5c26daded5", size = 74165, upload-time = "2026-05-22T00:16:16.698Z" }, +] + +[[package]] +name = "imageio" +version = "2.37.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "pillow" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/84/93bcd1300216ea50811cee96873b84a1bebf8d0489ffaf7f2a3756bab866/imageio-2.37.3.tar.gz", hash = "sha256:bbb37efbfc4c400fcd534b367b91fcd66d5da639aaa138034431a1c5e0a41451", size = 389673, upload-time = "2026-03-09T11:31:12.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/fa/391e437a34e55095173dca5f24070d89cbc233ff85bf1c29c93248c6588d/imageio-2.37.3-py3-none-any.whl", hash = "sha256:46f5bb8522cd421c0f5ae104d8268f569d856b29eb1a13b92829d1970f32c9f0", size = 317646, upload-time = "2026-03-09T11:31:10.771Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "ipython" +version = "9.13.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "decorator" }, + { name = "ipython-pygments-lexers" }, + { name = "jedi" }, + { name = "matplotlib-inline" }, + { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "prompt-toolkit" }, + { name = "psutil" }, + { name = "pygments" }, + { name = "stack-data" }, + { name = "traitlets" }, + { name = "typing-extensions", marker = "python_full_version < '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cd/c4/87cda5842cf5c31837c06ddb588e11c3c35d8ece89b7a0108c06b8c9b00a/ipython-9.13.0.tar.gz", hash = "sha256:7e834b6afc99f020e3f05966ced34792f40267d64cb1ea9043886dab0dde5967", size = 4430549, upload-time = "2026-04-24T12:24:55.221Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/86/3060e8029b7cc505cce9a0137431dda81d0a3fde93a8f0f50ee0bf37a795/ipython-9.13.0-py3-none-any.whl", hash = "sha256:57f9d4639e20818d328d287c7b549af3d05f12486ea8f2e7f73e52a36ec4d201", size = 627274, upload-time = "2026-04-24T12:24:53.038Z" }, +] + +[[package]] +name = "ipython-pygments-lexers" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" }, +] + +[[package]] +name = "ipywidgets" +version = "8.1.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "comm" }, + { name = "ipython" }, + { name = "jupyterlab-widgets" }, + { name = "traitlets" }, + { name = "widgetsnbextension" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4c/ae/c5ce1edc1afe042eadb445e95b0671b03cee61895264357956e61c0d2ac0/ipywidgets-8.1.8.tar.gz", hash = "sha256:61f969306b95f85fba6b6986b7fe45d73124d1d9e3023a8068710d47a22ea668", size = 116739, upload-time = "2025-11-01T21:18:12.393Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl", hash = "sha256:ecaca67aed704a338f88f67b1181b58f821ab5dc89c1f0f5ef99db43c1c2921e", size = 139808, upload-time = "2025-11-01T21:18:10.956Z" }, +] + +[[package]] +name = "jedi" +version = "0.20.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "parso" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/46/b7/a3635f6a2d7cf5b5dd98064fc1d5fbbafcb25477bcea204a3a92145d158b/jedi-0.20.0.tar.gz", hash = "sha256:c3f4ccbd276696f4b19c54618d4fb18f9fc24b0aef02acf704b23f487daa1011", size = 3119416, upload-time = "2026-05-01T23:38:47.814Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/93/242e2eab5fe682ffcb8b0084bde703a41d51e17ee0f3a31ff0d9d813620a/jedi-0.20.0-py2.py3-none-any.whl", hash = "sha256:7bdd9c2634f56713299976f4cbd59cb3fa92165cc5e05ea811fb253480728b67", size = 4884812, upload-time = "2026-05-01T23:38:43.919Z" }, +] + +[[package]] +name = "jiter" +version = "0.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/66/b5/55f06bb281d92fb3cc86d14e1def2bd908bb77693183e7cb1f5a3c388b0c/jiter-0.15.0.tar.gz", hash = "sha256:4251acc80e2b7c9b7b8823456ea0fceeb0734dac2df7636d3c711b38476b5a76", size = 166640, upload-time = "2026-05-19T10:09:48.361Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/13/daa722f5765c393576f466378f9dfd29d77c9bed939e0688f96afa3601ea/jiter-0.15.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0f862193b8696249d22ec433e85fd2ab0ad9596bc3e45e6c0bc55e8aeba97be2", size = 310899, upload-time = "2026-05-19T10:07:12.89Z" }, + { url = "https://files.pythonhosted.org/packages/7f/82/2d2551829b082f4b6d82b9f939b031fb808a10aab1ec0664f82e150bb9a2/jiter-0.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1303d4d68a9b051ea90502402063ecf3807da00ad2affa19ca1ae3b90b3c5f67", size = 314963, upload-time = "2026-05-19T10:07:14.539Z" }, + { url = "https://files.pythonhosted.org/packages/2a/0a/8b1a51466f7fe9f31dbe4bc7e0ca848674f9825e0f737b929b97e8c60aa7/jiter-0.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:392b8ab019e5502d08aff85c6272209c24bc2cbe706ea82a56368f524236614a", size = 341730, upload-time = "2026-05-19T10:07:15.869Z" }, + { url = "https://files.pythonhosted.org/packages/f6/2a/e71dea19822e2e404e83992a08c1d6b9b617bb944f28c9c2fbd85d02c91e/jiter-0.15.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:773b6eb282ce11ee19f05f6b2d4404fa308e5bbd353b0b80a0262caad6db2cd7", size = 366214, upload-time = "2026-05-19T10:07:17.259Z" }, + { url = "https://files.pythonhosted.org/packages/c4/59/97e1fa539d124a509a00ab7f669289d1c1d236ecabf12948a18f16c91082/jiter-0.15.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8d2c0c44d569ce0f2850f5c926f8caeb5f245fbc84475aeb36efccc2103e6dbd", size = 459527, upload-time = "2026-05-19T10:07:18.741Z" }, + { url = "https://files.pythonhosted.org/packages/d1/7a/4a68d331aef8cf2e2393c14a3aacb635c62aa86071b0229899fb5baaa907/jiter-0.15.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:032396229564bca02440396bd327710719f724f5e7b7e9f7a8eb3faa4a2c2281", size = 375451, upload-time = "2026-05-19T10:07:20.208Z" }, + { url = "https://files.pythonhosted.org/packages/7b/7e/1c445c2b6f0e30a274dc8082e0c3c7825411cce80d726bccd697c98cc8d3/jiter-0.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3d37768fce7f88dd2a8c6091f2325dea27d30d30d5c6e7a1c0f0af77723b708", size = 349428, upload-time = "2026-05-19T10:07:22.372Z" }, + { url = "https://files.pythonhosted.org/packages/00/94/e20d38984fc17a636371bffd2ae0f698124fdc8e75ef969cd2da6ba7cea7/jiter-0.15.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:2c9cb907439d20bd0c7d7565ca01ee52234203208433749bae5b516907526928", size = 355405, upload-time = "2026-05-19T10:07:23.916Z" }, + { url = "https://files.pythonhosted.org/packages/94/fa/4d09f814779d0ea80a28ed8e4c6662ec9a4a8ecef0ac52190ebac6262d14/jiter-0.15.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9100ddbec09741cc66feb0fc6773f8bdbd0e3c345689368f260082ff85dcc0cd", size = 393688, upload-time = "2026-05-19T10:07:25.854Z" }, + { url = "https://files.pythonhosted.org/packages/54/9d/8eb5d4fb8bf7e93a75964a5da71a75c67c864baf7fa3f98598187b3c7e57/jiter-0.15.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ae1b0d82ac2d987f9ea512b1c9adfcc71a28de3dea3a6039b54d76cffda9901e", size = 520853, upload-time = "2026-05-19T10:07:27.303Z" }, + { url = "https://files.pythonhosted.org/packages/e7/2c/5e07874e59e623a943a0acf1552a80d05b70f31b402287a8fc6d7ec634c7/jiter-0.15.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8020c99ec13a7db2b6f96cbe82ef4721c88b426a4892f27478044af0284615ef", size = 551016, upload-time = "2026-05-19T10:07:28.846Z" }, + { url = "https://files.pythonhosted.org/packages/22/ed/d2d34422143474cadc15b60d482b1c35683dbc5c63c24346ddd0df09bcaf/jiter-0.15.0-cp311-cp311-win32.whl", hash = "sha256:42bfb257930800cf43e7c62c832402c704ab60797c992faf88d20e903eac8f32", size = 209518, upload-time = "2026-05-19T10:07:30.431Z" }, + { url = "https://files.pythonhosted.org/packages/1d/7d/52778b930e5cc3e52a37d950b1c10494244308b4329b25a0ff0d88303a81/jiter-0.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:860a74063284a2ae9bfedd694f299cc2c68e2696c5f3d440cc9d18bb81b9dd04", size = 200565, upload-time = "2026-05-19T10:07:32.125Z" }, + { url = "https://files.pythonhosted.org/packages/3b/4f/d9b4067feb69b3fa6eb0488e1b59e2ad5b463fe39f59e527eab2aca00bb0/jiter-0.15.0-cp311-cp311-win_arm64.whl", hash = "sha256:37a10c377ce3a4a85f4a67f28b7afe093154cde77eaf248a72e856aa08b4d865", size = 195488, upload-time = "2026-05-19T10:07:33.846Z" }, + { url = "https://files.pythonhosted.org/packages/44/53/4f6bddbcde3c71e56d0aa1337ec95950f3d27dd4153e25aadf0feac71751/jiter-0.15.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0e90a1c315a0226ec822d973817967f9223b7701546c8c2a7913e7ab0926294d", size = 308793, upload-time = "2026-05-19T10:07:35.25Z" }, + { url = "https://files.pythonhosted.org/packages/01/84/c01099b59a285a1ebba64ae93f62bfa036675340fd1b0045ae65890a0442/jiter-0.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8c9004af7c8d67cce7f1aae1026fb55607f4aa600710d08ede3a3ce4aeefe7e0", size = 309570, upload-time = "2026-05-19T10:07:36.919Z" }, + { url = "https://files.pythonhosted.org/packages/58/64/8fb7f9d45bb98190355454cd04dad8d8f27223d6bd52f83af07f637168a6/jiter-0.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c210f8b35dc6f30aafd4b4365ca89b9d1189f21ab49b8e68fa6322a847aef138", size = 336783, upload-time = "2026-05-19T10:07:38.694Z" }, + { url = "https://files.pythonhosted.org/packages/c3/b6/f5739011d009b3a30f6a53c5240979030ba29ae46a8c67e3a15759f7c37d/jiter-0.15.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f30bae8bc1c2d613e28e5af3e8cceb09b742f1c8a8a5f839fb67afaffc03b61", size = 363555, upload-time = "2026-05-19T10:07:40.832Z" }, + { url = "https://files.pythonhosted.org/packages/e5/12/98a9d9f766665e8a3b6252454e17cb0c464606a28cf2fa09399b003345fa/jiter-0.15.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c60e71b6d10cfc284c9bf36bd885e8d44c46f688ce50aa91b5edd90181dea687", size = 452255, upload-time = "2026-05-19T10:07:42.62Z" }, + { url = "https://files.pythonhosted.org/packages/e8/d5/60f972840f79c5e7544fce567c56f1e4e50468f996baba3e78d823dd62a6/jiter-0.15.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ab068bce62a45aa3e7367eceaffb5dde60b7eb853be8dece45132e3d0ff4879", size = 373559, upload-time = "2026-05-19T10:07:44.201Z" }, + { url = "https://files.pythonhosted.org/packages/ee/cf/d46ef1234ba335aabc2f013210db8e0821a22f5e644a2e9449df199ecc23/jiter-0.15.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa248c9eb220197d363f688818dac2fd4b2f0cd7d843ca7105d652034823427d", size = 346055, upload-time = "2026-05-19T10:07:46.005Z" }, + { url = "https://files.pythonhosted.org/packages/f0/63/4d2749d8d54d230bad9b3a6b0d00cc28c6ff6b2fdffc26a8ccf76cc5a974/jiter-0.15.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:2a77aadd57cac1682e4401a72724d2796d89a4ba129b1a5812aa94ee480826eb", size = 351406, upload-time = "2026-05-19T10:07:47.855Z" }, + { url = "https://files.pythonhosted.org/packages/d9/b9/9965b990035d8773328e0a8c8b457a87bf2b19f6c4126d9d99296be5d16a/jiter-0.15.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2ae901f3a55bfafdde31d289590fa25e3245735a2b1e8c7cc15871710a002871", size = 389357, upload-time = "2026-05-19T10:07:49.665Z" }, + { url = "https://files.pythonhosted.org/packages/2d/55/9ddf903deda1413e87fed792f416b7123daee5b8efbad6a202a7421c36a5/jiter-0.15.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f0b271b462769543716f92d3a4f90527df6ef5ed05ee95ec4137f513e21e1b77", size = 517263, upload-time = "2026-05-19T10:07:51.537Z" }, + { url = "https://files.pythonhosted.org/packages/e8/76/a0c40ad064d3a20a4fde231e35d56e9a01ce82164278180e82d5daf85469/jiter-0.15.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2fb6a5d26af81fc0f00f9360a891e05cf755e149bba391c4d563adc54812973d", size = 548646, upload-time = "2026-05-19T10:07:53.196Z" }, + { url = "https://files.pythonhosted.org/packages/23/4f/eca9b954942916ba2f453891b8593ab444cd872396fe66a3936616f236f3/jiter-0.15.0-cp312-cp312-win32.whl", hash = "sha256:c2f6bb8b5216ab9e7873bc08b5d7bef2b8abbb578a3069bf1cd14a45d71d771d", size = 206427, upload-time = "2026-05-19T10:07:55.307Z" }, + { url = "https://files.pythonhosted.org/packages/95/bf/8ead82a87495149542748e828d153fd232a512a22c83b02c4815c1a9c7d8/jiter-0.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:40b2c7e92c44a84d748d21706c68dc6ff8161d80b59c99d774721a0d2317d7c7", size = 197300, upload-time = "2026-05-19T10:07:56.651Z" }, + { url = "https://files.pythonhosted.org/packages/f4/e4/9b8a78fb2d894471bc344e37f1949bdd784bd914d031dba0ba3a40c71dd7/jiter-0.15.0-cp312-cp312-win_arm64.whl", hash = "sha256:cc0bc345cf2df9d1c00ac443f50d543c1ccfa8b0422cb85b1ab70d681c0b255b", size = 192702, upload-time = "2026-05-19T10:07:58.307Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f4/f708c900ecee41b2025ef8413d5351e5649eb2125c506f6720cc69b06f5c/jiter-0.15.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1c11465f97e2abf45a014b83b730222f8f1c5335e802c7055a67d50de6f1f4e3", size = 307829, upload-time = "2026-05-19T10:07:59.704Z" }, + { url = "https://files.pythonhosted.org/packages/86/59/db537c0949e83668c38481d426b9f2fd5ab758c4ee53a811dd0a510626a0/jiter-0.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d1e7b1776f0797956c509e123d0952d10d293a9492dea9f288ab9570ec01d1a5", size = 308445, upload-time = "2026-05-19T10:08:01.184Z" }, + { url = "https://files.pythonhosted.org/packages/37/38/ea0e13b18c30ef951da0d47d39e7fa9edb82a93a62990ffbd7cea9b622d4/jiter-0.15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:351a341c2105aa430b7047e30f1bf7975f6313b00165d3fc07be2edaf741f279", size = 336181, upload-time = "2026-05-19T10:08:02.688Z" }, + { url = "https://files.pythonhosted.org/packages/58/fc/2303901b16c4ba05865588990a420c0b4156270b44379c20931544a1d962/jiter-0.15.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4ab395feec8d249ec4044e228e98a7033f043426a265df439dc3698823f0a4e4", size = 362985, upload-time = "2026-05-19T10:08:04.394Z" }, + { url = "https://files.pythonhosted.org/packages/5b/6f/11bace093c52e7d4d26c8e606ccd7ae8c972189622469ec0d9e28161e28b/jiter-0.15.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2a438005b6f22d0273413484d6094d7c2c5d10ec1b3a3bf128e0d1d3ba53258", size = 453292, upload-time = "2026-05-19T10:08:05.967Z" }, + { url = "https://files.pythonhosted.org/packages/22/db/987f2f086ca4d7a6582eb4ccd513f9b26b42d9e4243a087609a3137a8fc7/jiter-0.15.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f18f85e4218d1b40f000f42a92239a7a61a902cd42c65e6c360dbd17dcb20894", size = 373501, upload-time = "2026-05-19T10:08:07.857Z" }, + { url = "https://files.pythonhosted.org/packages/8f/7c/89fbcabb2739b7a5b8dc959a1b6c5761f6484f5fed3486854b3c789bb1de/jiter-0.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1aa62e277fc1cbd80e6deacae6f4d983b41b3d7728e0645c5d741a6149bba45", size = 344683, upload-time = "2026-05-19T10:08:09.431Z" }, + { url = "https://files.pythonhosted.org/packages/30/6f/6cca7692e7dddfec6d8d76c54dc97f2af2a41df4ac0674b999df1f09a5f3/jiter-0.15.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:6550fa135c7deb8ead6af49ed7ff648532ea8334a1447fe34a36315ef79c5c29", size = 350892, upload-time = "2026-05-19T10:08:11.352Z" }, + { url = "https://files.pythonhosted.org/packages/39/14/0338d6190cb8e6d22e677ab1d4eabd4117f67cca70c54cd04b82ff64e068/jiter-0.15.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:066f8f33f18b2419cd8213b2436fa7fbc9c499f315971cfa3ce1f9820c001b1b", size = 388723, upload-time = "2026-05-19T10:08:12.912Z" }, + { url = "https://files.pythonhosted.org/packages/90/31/cc19f4a1bdb6afb09ce6a2f2615aa8d44d994eba0d8e6105ed1af920e736/jiter-0.15.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:75e8a04e91432dde9f1838373cf93d23726c79d3e908d319acf0e796f85592e7", size = 516648, upload-time = "2026-05-19T10:08:14.808Z" }, + { url = "https://files.pythonhosted.org/packages/49/9f/833c541512cd091b63c10c0381973dfe11bc7a503a818c16384417e0c81e/jiter-0.15.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:a97261f1fccb8e50ecd2890a96e46efdc3f57c80a197324c6777827231eca712", size = 547382, upload-time = "2026-05-19T10:08:16.927Z" }, + { url = "https://files.pythonhosted.org/packages/d2/11/e7b70e91f90bc4477e8eee9e8a5f7cf3cb41b4525d6394dc98a714eb8f7f/jiter-0.15.0-cp313-cp313-win32.whl", hash = "sha256:c77496cb10bd7549690fbbab3e5ec05857b83e49276f4a9423a766ddd2afcd4c", size = 205845, upload-time = "2026-05-19T10:08:18.401Z" }, + { url = "https://files.pythonhosted.org/packages/4b/23/5c20d9ad6f02c493e4023e5d2d09e1c1f15fe2753c9102c544aff068a88e/jiter-0.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:b15741f501469009ae0ae90b7147958a664a7dede40aa7ff174a8a4645f546d0", size = 196842, upload-time = "2026-05-19T10:08:20.131Z" }, + { url = "https://files.pythonhosted.org/packages/6b/11/1eb400ef248e8c925fd883fbe325daf5e42cd1b0d308539dd332bd4f7ffc/jiter-0.15.0-cp313-cp313-win_arm64.whl", hash = "sha256:5d6a60072b44c3c2b797a7ddcbcbbf2b34ea3cfd4721580fbfd2a09d9d9b84ba", size = 192212, upload-time = "2026-05-19T10:08:21.807Z" }, + { url = "https://files.pythonhosted.org/packages/8a/60/2fd8d7c79da8acf9b7b277c7616847773779356b92acfc9bb158452174da/jiter-0.15.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:ef1fd24d9413f6209e00d3d5a453e67acfe004a25cc6c8e8484faed4311ab9e8", size = 315065, upload-time = "2026-05-19T10:08:23.218Z" }, + { url = "https://files.pythonhosted.org/packages/46/f4/008fb7d65e8ac2abf00811651a661e025c4ba80bbc6f378450384ddd3aed/jiter-0.15.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:144f8e72cb53dab146347b91cceac01f5481237f2b93b4a339a1ee8f8878b67c", size = 339444, upload-time = "2026-05-19T10:08:24.701Z" }, + { url = "https://files.pythonhosted.org/packages/00/55/90b0c7b9c6896c0f2a591dd36d36b71d22e09674bfef178fa03ba3f81499/jiter-0.15.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:553fcac2ef2cb990877f9fc0833b8b629a3e6a5670b6b5fd58219b41a653ddc4", size = 347779, upload-time = "2026-05-19T10:08:26.408Z" }, + { url = "https://files.pythonhosted.org/packages/51/6b/69666cec5000fd57734c118437394516c749ae8dbeea9fb66d6fef9c4775/jiter-0.15.0-cp313-cp313t-win_amd64.whl", hash = "sha256:774f93f65031856bf14ad9f59bdcab8b8cad501e5ceabd51ba3525f76937a25b", size = 200395, upload-time = "2026-05-19T10:08:28.055Z" }, + { url = "https://files.pythonhosted.org/packages/39/04/a6aa62cd27e8149b0d28df5561f10f6cceaf7935a9ccf3f1c5a05f9a0cd8/jiter-0.15.0-cp313-cp313t-win_arm64.whl", hash = "sha256:f1e1754960f38ec40613a07e5e372df67acb3b890fb383b6fb3de3e49ddbf3c7", size = 190516, upload-time = "2026-05-19T10:08:29.35Z" }, + { url = "https://files.pythonhosted.org/packages/eb/d2/079f350ebf7859d081de30aa890f9e3be68516f754f3ba32366ffff4dcee/jiter-0.15.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:ac0d9ddea4350974be7a221fc25895f251a8fee748c889bdced2141c0fec1a49", size = 308884, upload-time = "2026-05-19T10:08:31.667Z" }, + { url = "https://files.pythonhosted.org/packages/04/4e/a2c30a7f69b48c03b20935d647479106fe932f6e63f75faf53937197e05d/jiter-0.15.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:01a8222cf05ab1128e239421156c207949808acaaea2bdfd33130ae666786e86", size = 310028, upload-time = "2026-05-19T10:08:33.304Z" }, + { url = "https://files.pythonhosted.org/packages/40/90/2e7cdfd3cf8ca967be38c48f5cf474d79f089efaf559a40f15984a77ae69/jiter-0.15.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:182226cbc930c9fab81bc2e41a4da672f89539906dadb05e75670ac07b94f71f", size = 337485, upload-time = "2026-05-19T10:08:35.259Z" }, + { url = "https://files.pythonhosted.org/packages/9b/11/15a1aa28b120b8ee5b4f1fb894c125046225f09847738bd64233d3b84883/jiter-0.15.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:71683c38c825452999b5717fcae07ea708e8c93003e808be4319c1b02e3d176e", size = 364223, upload-time = "2026-05-19T10:08:36.694Z" }, + { url = "https://files.pythonhosted.org/packages/b7/25/f442e8af5f3d0dcf47b39e83a0efd9ee45ea946aa6d04625dc3181eae3b6/jiter-0.15.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30f2218e6a9e5c18bc10fe6d41ac189c442c88eacf11bad9f28ef95a9bef00e6", size = 456387, upload-time = "2026-05-19T10:08:38.143Z" }, + { url = "https://files.pythonhosted.org/packages/da/f4/37f2d2c9f64f49af7da652ed7532bb5a2372e588e6927c3fdd76f911db65/jiter-0.15.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5157de9f76eb4bc5ea74a1219366a25f945ad305641d74e04f59c54087091aa9", size = 374461, upload-time = "2026-05-19T10:08:39.869Z" }, + { url = "https://files.pythonhosted.org/packages/60/28/edcfbbbf0cb15436f36664a8908a0df47ab9006298d4cd937dc08ea932d6/jiter-0.15.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c5db5527c221249a876160663ab891ace358c17f7b9c93ec1478b7f0550e5c", size = 345924, upload-time = "2026-05-19T10:08:41.668Z" }, + { url = "https://files.pythonhosted.org/packages/47/13/89fba6398dab7f202b7278c4b4aac122399d2c0183971c4a57a3b7088df5/jiter-0.15.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:3e4540b8e74e4268811ac05db226a6a128ff572e7e0ce3f1163b693cadb184cd", size = 352283, upload-time = "2026-05-19T10:08:43.091Z" }, + { url = "https://files.pythonhosted.org/packages/1b/da/0f6af8cef2c565a1ab44d970f268c43ccaa72707386ea6388e6fe2b6cd26/jiter-0.15.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:62ebd14e47e9aed9df4472afcb2663668ce4d74891cd54f86bf6e44029d6dc89", size = 389985, upload-time = "2026-05-19T10:08:44.915Z" }, + { url = "https://files.pythonhosted.org/packages/a1/ec/b9cb7d6d29e24ee14910266157d2a279d7a8f60ee0df7fa840882976ba64/jiter-0.15.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0be6f5ad41a809f303f416d17cec92a7a725902fb9b4f3de3d19362ac0ef8554", size = 517695, upload-time = "2026-05-19T10:08:46.486Z" }, + { url = "https://files.pythonhosted.org/packages/64/5e/6d1bda880723aae0ad86b4b763f044362448efe31e3e819635d41cb03451/jiter-0.15.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:813dfbb17d65328bf86e5f0905dd277ba2265d3ca20556e86c0c7035b7182e5a", size = 548868, upload-time = "2026-05-19T10:08:48.026Z" }, + { url = "https://files.pythonhosted.org/packages/0c/72/7de501cf38dcacaf35098796f3a50e0f2e338baba18a58946c618544b809/jiter-0.15.0-cp314-cp314-win32.whl", hash = "sha256:50e51156192722a9c58db112837d3f8ef96fb3c5ecc14e95f409134b08b158ec", size = 206380, upload-time = "2026-05-19T10:08:49.738Z" }, + { url = "https://files.pythonhosted.org/packages/1e/a9/e19addf4b0c1bdce52c6da12351e6bc42c340c45e7c09e2158e46d293ccc/jiter-0.15.0-cp314-cp314-win_amd64.whl", hash = "sha256:30ce1a5d16b5641dc935d50ef775af6a0871e3d14ab05d6fc54dff371b78e558", size = 197687, upload-time = "2026-05-19T10:08:51.088Z" }, + { url = "https://files.pythonhosted.org/packages/f2/c9/776b1db01db25fc6c1d58d1979a37b0a9fe787e5f5b1d062d2eaacb77923/jiter-0.15.0-cp314-cp314-win_arm64.whl", hash = "sha256:510c8b3c17a0ed9ac69850c0438dada3c9b82d9c4d589fcb62002a5a9cf3a866", size = 192571, upload-time = "2026-05-19T10:08:52.451Z" }, + { url = "https://files.pythonhosted.org/packages/a0/f6/45bb4670bacf300fd2c7abadbfb3af376e5f1b6ae75fd9bc069891d15870/jiter-0.15.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7553333dd0930c104a5a0db8df72bf7219fe663d731383b576bb6ed6351c984d", size = 317151, upload-time = "2026-05-19T10:08:53.867Z" }, + { url = "https://files.pythonhosted.org/packages/d7/68/ed635ad5acd7b73e454283083bbb7c8205ad10e88b0d9d7d793b09fe8226/jiter-0.15.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2143ab06181d2b029eedcb6af3cebe95f11bbac62441781860f98ee9330a6a6", size = 341243, upload-time = "2026-05-19T10:08:55.383Z" }, + { url = "https://files.pythonhosted.org/packages/5d/db/3ff4176b817b8ea33879e71e13d8bc2b0d481a7ed3fe9e080f333d415c16/jiter-0.15.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6eac374c5c975709b69c10f09afd199df74150172156ad10c8d4fd785b7da995", size = 363629, upload-time = "2026-05-19T10:08:56.928Z" }, + { url = "https://files.pythonhosted.org/packages/ab/24/5f8270e0ba9c883582f96f722f8a0b58015c7ce1f8c6d4571cf394e99b6b/jiter-0.15.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b3b3b775e33d3bfaec9899edc526ae97b0da0bf9d071a46124ba419149a414f8", size = 456198, upload-time = "2026-05-19T10:08:58.618Z" }, + { url = "https://files.pythonhosted.org/packages/45/5b/76fc02b0b5c54c3d18c60653156e2f76fde1816f9b4722db68d6ee2c897e/jiter-0.15.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3071db3346334beae1360b46da4606da57bf3528c167b3c38533afaf9f2c5", size = 373710, upload-time = "2026-05-19T10:09:00.151Z" }, + { url = "https://files.pythonhosted.org/packages/c4/52/4310821b0ea9277994d3e1f49fc6a4b34e4800caebacb2c0af81da59a454/jiter-0.15.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6694a173ecabc12eb60efbc0b474464ead1951ff65cd8b1e72100715c64512b", size = 349901, upload-time = "2026-05-19T10:09:01.621Z" }, + { url = "https://files.pythonhosted.org/packages/93/fe/67648c35b3594fba8854ac64cc8a826d8bcd18324bbdb53d77697c60b6ef/jiter-0.15.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:a254e10b593624d230c365b6d616b22ca0ad65e63a16e6631c2b3466022e6ba8", size = 352438, upload-time = "2026-05-19T10:09:03.216Z" }, + { url = "https://files.pythonhosted.org/packages/cb/28/0a1879d07ad6b3e025a2750027363452ced93c2d16d1c9d4b153ffd51c91/jiter-0.15.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d8d2955167274e15d79a7a020afdd9b39c990eb80b2d89fca695d92dcfdd38ec", size = 388152, upload-time = "2026-05-19T10:09:04.741Z" }, + { url = "https://files.pythonhosted.org/packages/c1/78/46c6f6b56ba85c90021f4afd72ed42f691f8f84daacb5fe27277070e3858/jiter-0.15.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:acf4ee4d1fc55917239fe72972fb292dd773055d05eb040d36f4326e02cc2c0e", size = 517707, upload-time = "2026-05-19T10:09:06.231Z" }, + { url = "https://files.pythonhosted.org/packages/ca/cb/720662d4c88fcad606e826fef5424365527ba43ce4868a479aed8f8c507e/jiter-0.15.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:e7196e56f1cd69af1dbb07dff02dcfb260a50b45a82d409d92a06fedb32473b5", size = 548241, upload-time = "2026-05-19T10:09:08.093Z" }, + { url = "https://files.pythonhosted.org/packages/60/e3/935b8034fd143f21125c87d51404a9e0e1449186a494405721ff5d1d695e/jiter-0.15.0-cp314-cp314t-win32.whl", hash = "sha256:7f6163c0f10b055245f814dcc59f4818da60dfe72f3e72ab89fc24b6bd5e9c52", size = 207950, upload-time = "2026-05-19T10:09:09.616Z" }, + { url = "https://files.pythonhosted.org/packages/93/59/984fd9ece895953dad3e0880a650e766f5a2da2c5514f0eafdaaabbeb5f9/jiter-0.15.0-cp314-cp314t-win_amd64.whl", hash = "sha256:980c256edb05b78a111b99c4de3b1d32e31634b867fd1fc2cf726e7b7bba9854", size = 200055, upload-time = "2026-05-19T10:09:11.367Z" }, + { url = "https://files.pythonhosted.org/packages/0e/a4/cf8d779feb133a27a2e3bc833bccb9e13aa332cdf820497ebf72c10ce8c3/jiter-0.15.0-cp314-cp314t-win_arm64.whl", hash = "sha256:66b1880df2d01e206e8339769d1c7c1753bcb653efd6289e203f6f24ebada0c0", size = 191244, upload-time = "2026-05-19T10:09:12.74Z" }, + { url = "https://files.pythonhosted.org/packages/65/43/1fc62172aa98b50a7de9a25554060db510f85c89cfbed0dfe13e1907a139/jiter-0.15.0-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:411fa4dfa5a7ae3d11491027ffb9beadec3996010a986862db70d91abba1c750", size = 305585, upload-time = "2026-05-19T10:09:35.995Z" }, + { url = "https://files.pythonhosted.org/packages/e8/c4/dd58fcd9e2df83666e5c1c1347bef58ce919cd8efc3ffa38aeea62ce493b/jiter-0.15.0-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:2b0074e2f56eb2dacca1689760fd2852a068f85a0547a157b82cb4cafeb6768b", size = 306936, upload-time = "2026-05-19T10:09:37.435Z" }, + { url = "https://files.pythonhosted.org/packages/39/86/b695e16f1180c07f43ea98e73ecd21cf63fa2e1b0c1103739013784d11ae/jiter-0.15.0-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:913d02d29c9606643418d9ccfc3b72492ab25a6bf7889934e09a3490f8d3438b", size = 342453, upload-time = "2026-05-19T10:09:39.294Z" }, + { url = "https://files.pythonhosted.org/packages/34/56/55d76614af37fe3f22a3347d1e410d2a15da581997cb2da499a625000bb5/jiter-0.15.0-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b15d3ec9b0449c40e85319bdb4caa8b77ab526e74f5532ed94bec15e2f66822c", size = 345606, upload-time = "2026-05-19T10:09:40.727Z" }, + { url = "https://files.pythonhosted.org/packages/73/38/505941b2b092fd5bbbd60a52a880db1173f1690ae6751bed3af1c9ddcb4e/jiter-0.15.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:631f13a3d04e97d4e083993b10f4b99530e3a10d953e2eb5e196b7dc7f812ce0", size = 303769, upload-time = "2026-05-19T10:09:42.203Z" }, + { url = "https://files.pythonhosted.org/packages/e7/95/a06692b29e77473f286e1ec1f426d3ca44d7b5843be8ad21d7a5f3fcdcc0/jiter-0.15.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:b6c0ffae686c39bf3737be60793783267628783ea42545632c10b291105aee45", size = 305128, upload-time = "2026-05-19T10:09:43.657Z" }, + { url = "https://files.pythonhosted.org/packages/23/85/7270d7ad41d6061a25b950c6bf91d638bd9aacb113200a8c8d57a055fd67/jiter-0.15.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d54fb5b31dea401a41af3f8a7d2512e9b6a6a005491e6166c7e4ffab9639a9c", size = 340459, upload-time = "2026-05-19T10:09:45.452Z" }, + { url = "https://files.pythonhosted.org/packages/c8/8d/302cb2057b7513327b4d575cff6b1d066ee6431a5357fc3f8867cd684406/jiter-0.15.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54d5d6090cdc1b7c9e780dfb04949a990adb1e301a2fc0bbcee7de4638d33f9a", size = 344469, upload-time = "2026-05-19T10:09:46.864Z" }, +] + +[[package]] +name = "joblib" +version = "1.5.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/41/f2/d34e8b3a08a9cc79a50b2208a93dce981fe615b64d5a4d4abee421d898df/joblib-1.5.3.tar.gz", hash = "sha256:8561a3269e6801106863fd0d6d84bb737be9e7631e33aaed3fb9ce5953688da3", size = 331603, upload-time = "2025-12-15T08:41:46.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713", size = 309071, upload-time = "2025-12-15T08:41:44.973Z" }, +] + +[[package]] +name = "jupyterlab-widgets" +version = "3.0.16" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/26/2d/ef58fed122b268c69c0aa099da20bc67657cdfb2e222688d5731bd5b971d/jupyterlab_widgets-3.0.16.tar.gz", hash = "sha256:423da05071d55cf27a9e602216d35a3a65a3e41cdf9c5d3b643b814ce38c19e0", size = 897423, upload-time = "2025-11-01T21:11:29.724Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl", hash = "sha256:45fa36d9c6422cf2559198e4db481aa243c7a32d9926b500781c830c80f7ecf8", size = 914926, upload-time = "2025-11-01T21:11:28.008Z" }, +] + +[[package]] +name = "kiwisolver" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/67/9c61eccb13f0bdca9307614e782fec49ffdde0f7a2314935d489fa93cd9c/kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a", size = 103482, upload-time = "2026-03-09T13:15:53.382Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/dd/a495a9c104be1c476f0386e714252caf2b7eca883915422a64c50b88c6f5/kiwisolver-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9eed0f7edbb274413b6ee781cca50541c8c0facd3d6fd289779e494340a2b85c", size = 122798, upload-time = "2026-03-09T13:12:58.963Z" }, + { url = "https://files.pythonhosted.org/packages/11/60/37b4047a2af0cf5ef6d8b4b26e91829ae6fc6a2d1f74524bcb0e7cd28a32/kiwisolver-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c4923e404d6bcd91b6779c009542e5647fef32e4a5d75e115e3bbac6f2335eb", size = 66216, upload-time = "2026-03-09T13:13:00.155Z" }, + { url = "https://files.pythonhosted.org/packages/0a/aa/510dc933d87767584abfe03efa445889996c70c2990f6f87c3ebaa0a18c5/kiwisolver-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0df54df7e686afa55e6f21fb86195224a6d9beb71d637e8d7920c95cf0f89aac", size = 63911, upload-time = "2026-03-09T13:13:01.671Z" }, + { url = "https://files.pythonhosted.org/packages/80/46/bddc13df6c2a40741e0cc7865bb1c9ed4796b6760bd04ce5fae3928ef917/kiwisolver-1.5.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2517e24d7315eb51c10664cdb865195df38ab74456c677df67bb47f12d088a27", size = 1438209, upload-time = "2026-03-09T13:13:03.385Z" }, + { url = "https://files.pythonhosted.org/packages/fd/d6/76621246f5165e5372f02f5e6f3f48ea336a8f9e96e43997d45b240ed8cd/kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff710414307fefa903e0d9bdf300972f892c23477829f49504e59834f4195398", size = 1248888, upload-time = "2026-03-09T13:13:05.231Z" }, + { url = "https://files.pythonhosted.org/packages/b2/c1/31559ec6fb39a5b48035ce29bb63ade628f321785f38c384dee3e2c08bc1/kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6176c1811d9d5a04fa391c490cc44f451e240697a16977f11c6f722efb9041db", size = 1266304, upload-time = "2026-03-09T13:13:06.743Z" }, + { url = "https://files.pythonhosted.org/packages/5e/ef/1cb8276f2d29cc6a41e0a042f27946ca347d3a4a75acf85d0a16aa6dcc82/kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50847dca5d197fcbd389c805aa1a1cf32f25d2e7273dc47ab181a517666b68cc", size = 1319650, upload-time = "2026-03-09T13:13:08.607Z" }, + { url = "https://files.pythonhosted.org/packages/4c/e4/5ba3cecd7ce6236ae4a80f67e5d5531287337d0e1f076ca87a5abe4cd5d0/kiwisolver-1.5.0-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:01808c6d15f4c3e8559595d6d1fe6411c68e4a3822b4b9972b44473b24f4e679", size = 970949, upload-time = "2026-03-09T13:13:10.299Z" }, + { url = "https://files.pythonhosted.org/packages/5a/69/dc61f7ae9a2f071f26004ced87f078235b5507ab6e5acd78f40365655034/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f1f9f4121ec58628c96baa3de1a55a4e3a333c5102c8e94b64e23bf7b2083309", size = 2199125, upload-time = "2026-03-09T13:13:11.841Z" }, + { url = "https://files.pythonhosted.org/packages/e5/7b/abbe0f1b5afa85f8d084b73e90e5f801c0939eba16ac2e49af7c61a6c28d/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b7d335370ae48a780c6e6a6bbfa97342f563744c39c35562f3f367665f5c1de2", size = 2293783, upload-time = "2026-03-09T13:13:14.399Z" }, + { url = "https://files.pythonhosted.org/packages/8a/80/5908ae149d96d81580d604c7f8aefd0e98f4fd728cf172f477e9f2a81744/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:800ee55980c18545af444d93fdd60c56b580db5cc54867d8cbf8a1dc0829938c", size = 1960726, upload-time = "2026-03-09T13:13:16.047Z" }, + { url = "https://files.pythonhosted.org/packages/84/08/a78cb776f8c085b7143142ce479859cfec086bd09ee638a317040b6ef420/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c438f6ca858697c9ab67eb28246c92508af972e114cac34e57a6d4ba17a3ac08", size = 2464738, upload-time = "2026-03-09T13:13:17.897Z" }, + { url = "https://files.pythonhosted.org/packages/b1/e1/65584da5356ed6cb12c63791a10b208860ac40a83de165cb6a6751a686e3/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8c63c91f95173f9c2a67c7c526b2cea976828a0e7fced9cdcead2802dc10f8a4", size = 2270718, upload-time = "2026-03-09T13:13:19.421Z" }, + { url = "https://files.pythonhosted.org/packages/be/6c/28f17390b62b8f2f520e2915095b3c94d88681ecf0041e75389d9667f202/kiwisolver-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:beb7f344487cdcb9e1efe4b7a29681b74d34c08f0043a327a74da852a6749e7b", size = 73480, upload-time = "2026-03-09T13:13:20.818Z" }, + { url = "https://files.pythonhosted.org/packages/d8/0e/2ee5debc4f77a625778fec5501ff3e8036fe361b7ee28ae402a485bb9694/kiwisolver-1.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:ad4ae4ffd1ee9cd11357b4c66b612da9888f4f4daf2f36995eda64bd45370cac", size = 64930, upload-time = "2026-03-09T13:13:21.997Z" }, + { url = "https://files.pythonhosted.org/packages/4d/b2/818b74ebea34dabe6d0c51cb1c572e046730e64844da6ed646d5298c40ce/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4e9750bc21b886308024f8a54ccb9a2cc38ac9fa813bf4348434e3d54f337ff9", size = 123158, upload-time = "2026-03-09T13:13:23.127Z" }, + { url = "https://files.pythonhosted.org/packages/bf/d9/405320f8077e8e1c5c4bd6adc45e1e6edf6d727b6da7f2e2533cf58bff71/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:72ec46b7eba5b395e0a7b63025490d3214c11013f4aacb4f5e8d6c3041829588", size = 66388, upload-time = "2026-03-09T13:13:24.765Z" }, + { url = "https://files.pythonhosted.org/packages/99/9f/795fedf35634f746151ca8839d05681ceb6287fbed6cc1c9bf235f7887c2/kiwisolver-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ed3a984b31da7481b103f68776f7128a89ef26ed40f4dc41a2223cda7fb24819", size = 64068, upload-time = "2026-03-09T13:13:25.878Z" }, + { url = "https://files.pythonhosted.org/packages/c4/13/680c54afe3e65767bed7ec1a15571e1a2f1257128733851ade24abcefbcc/kiwisolver-1.5.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb5136fb5352d3f422df33f0c879a1b0c204004324150cc3b5e3c4f310c9049f", size = 1477934, upload-time = "2026-03-09T13:13:27.166Z" }, + { url = "https://files.pythonhosted.org/packages/c8/2f/cebfcdb60fd6a9b0f6b47a9337198bcbad6fbe15e68189b7011fd914911f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2af221f268f5af85e776a73d62b0845fc8baf8ef0abfae79d29c77d0e776aaf", size = 1278537, upload-time = "2026-03-09T13:13:28.707Z" }, + { url = "https://files.pythonhosted.org/packages/f2/0d/9b782923aada3fafb1d6b84e13121954515c669b18af0c26e7d21f579855/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b0f172dc8ffaccb8522d7c5d899de00133f2f1ca7b0a49b7da98e901de87bf2d", size = 1296685, upload-time = "2026-03-09T13:13:30.528Z" }, + { url = "https://files.pythonhosted.org/packages/27/70/83241b6634b04fe44e892688d5208332bde130f38e610c0418f9ede47ded/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6ab8ba9152203feec73758dad83af9a0bbe05001eb4639e547207c40cfb52083", size = 1346024, upload-time = "2026-03-09T13:13:32.818Z" }, + { url = "https://files.pythonhosted.org/packages/e4/db/30ed226fb271ae1a6431fc0fe0edffb2efe23cadb01e798caeb9f2ceae8f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:cdee07c4d7f6d72008d3f73b9bf027f4e11550224c7c50d8df1ae4a37c1402a6", size = 987241, upload-time = "2026-03-09T13:13:34.435Z" }, + { url = "https://files.pythonhosted.org/packages/ec/bd/c314595208e4c9587652d50959ead9e461995389664e490f4dce7ff0f782/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7c60d3c9b06fb23bd9c6139281ccbdc384297579ae037f08ae90c69f6845c0b1", size = 2227742, upload-time = "2026-03-09T13:13:36.4Z" }, + { url = "https://files.pythonhosted.org/packages/c1/43/0499cec932d935229b5543d073c2b87c9c22846aab48881e9d8d6e742a2d/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e315e5ec90d88e140f57696ff85b484ff68bb311e36f2c414aa4286293e6dee0", size = 2323966, upload-time = "2026-03-09T13:13:38.204Z" }, + { url = "https://files.pythonhosted.org/packages/3d/6f/79b0d760907965acfd9d61826a3d41f8f093c538f55cd2633d3f0db269f6/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:1465387ac63576c3e125e5337a6892b9e99e0627d52317f3ca79e6930d889d15", size = 1977417, upload-time = "2026-03-09T13:13:39.966Z" }, + { url = "https://files.pythonhosted.org/packages/ab/31/01d0537c41cb75a551a438c3c7a80d0c60d60b81f694dac83dd436aec0d0/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:530a3fd64c87cffa844d4b6b9768774763d9caa299e9b75d8eca6a4423b31314", size = 2491238, upload-time = "2026-03-09T13:13:41.698Z" }, + { url = "https://files.pythonhosted.org/packages/e4/34/8aefdd0be9cfd00a44509251ba864f5caf2991e36772e61c408007e7f417/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1d9daea4ea6b9be74fe2f01f7fbade8d6ffab263e781274cffca0dba9be9eec9", size = 2294947, upload-time = "2026-03-09T13:13:43.343Z" }, + { url = "https://files.pythonhosted.org/packages/ad/cf/0348374369ca588f8fe9c338fae49fa4e16eeb10ffb3d012f23a54578a9e/kiwisolver-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:f18c2d9782259a6dc132fdc7a63c168cbc74b35284b6d75c673958982a378384", size = 73569, upload-time = "2026-03-09T13:13:45.792Z" }, + { url = "https://files.pythonhosted.org/packages/28/26/192b26196e2316e2bd29deef67e37cdf9870d9af8e085e521afff0fed526/kiwisolver-1.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:f7c7553b13f69c1b29a5bde08ddc6d9d0c8bfb84f9ed01c30db25944aeb852a7", size = 64997, upload-time = "2026-03-09T13:13:46.878Z" }, + { url = "https://files.pythonhosted.org/packages/9d/69/024d6711d5ba575aa65d5538042e99964104e97fa153a9f10bc369182bc2/kiwisolver-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:fd40bb9cd0891c4c3cb1ddf83f8bbfa15731a248fdc8162669405451e2724b09", size = 123166, upload-time = "2026-03-09T13:13:48.032Z" }, + { url = "https://files.pythonhosted.org/packages/ce/48/adbb40df306f587054a348831220812b9b1d787aff714cfbc8556e38fccd/kiwisolver-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c0e1403fd7c26d77c1f03e096dc58a5c726503fa0db0456678b8668f76f521e3", size = 66395, upload-time = "2026-03-09T13:13:49.365Z" }, + { url = "https://files.pythonhosted.org/packages/a8/3a/d0a972b34e1c63e2409413104216cd1caa02c5a37cb668d1687d466c1c45/kiwisolver-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dda366d548e89a90d88a86c692377d18d8bd64b39c1fb2b92cb31370e2896bbd", size = 64065, upload-time = "2026-03-09T13:13:50.562Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0a/7b98e1e119878a27ba8618ca1e18b14f992ff1eda40f47bccccf4de44121/kiwisolver-1.5.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:332b4f0145c30b5f5ad9374881133e5aa64320428a57c2c2b61e9d891a51c2f3", size = 1477903, upload-time = "2026-03-09T13:13:52.084Z" }, + { url = "https://files.pythonhosted.org/packages/18/d8/55638d89ffd27799d5cc3d8aa28e12f4ce7a64d67b285114dbedc8ea4136/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c50b89ffd3e1a911c69a1dd3de7173c0cd10b130f56222e57898683841e4f96", size = 1278751, upload-time = "2026-03-09T13:13:54.673Z" }, + { url = "https://files.pythonhosted.org/packages/b8/97/b4c8d0d18421ecceba20ad8701358453b88e32414e6f6950b5a4bad54e65/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4db576bb8c3ef9365f8b40fe0f671644de6736ae2c27a2c62d7d8a1b4329f099", size = 1296793, upload-time = "2026-03-09T13:13:56.287Z" }, + { url = "https://files.pythonhosted.org/packages/c4/10/f862f94b6389d8957448ec9df59450b81bec4abb318805375c401a1e6892/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0b85aad90cea8ac6797a53b5d5f2e967334fa4d1149f031c4537569972596cb8", size = 1346041, upload-time = "2026-03-09T13:13:58.269Z" }, + { url = "https://files.pythonhosted.org/packages/a3/6a/f1650af35821eaf09de398ec0bc2aefc8f211f0cda50204c9f1673741ba9/kiwisolver-1.5.0-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:d36ca54cb4c6c4686f7cbb7b817f66f5911c12ddb519450bbe86707155028f87", size = 987292, upload-time = "2026-03-09T13:13:59.871Z" }, + { url = "https://files.pythonhosted.org/packages/de/19/d7fb82984b9238115fe629c915007be608ebd23dc8629703d917dbfaffd4/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:38f4a703656f493b0ad185211ccfca7f0386120f022066b018eb5296d8613e23", size = 2227865, upload-time = "2026-03-09T13:14:01.401Z" }, + { url = "https://files.pythonhosted.org/packages/7f/b9/46b7f386589fd222dac9e9de9c956ce5bcefe2ee73b4e79891381dda8654/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3ac2360e93cb41be81121755c6462cff3beaa9967188c866e5fce5cf13170859", size = 2324369, upload-time = "2026-03-09T13:14:02.972Z" }, + { url = "https://files.pythonhosted.org/packages/92/8b/95e237cf3d9c642960153c769ddcbe278f182c8affb20cecc1cc983e7cc5/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c95cab08d1965db3d84a121f1c7ce7479bdd4072c9b3dafd8fecce48a2e6b902", size = 1977989, upload-time = "2026-03-09T13:14:04.503Z" }, + { url = "https://files.pythonhosted.org/packages/1b/95/980c9df53501892784997820136c01f62bc1865e31b82b9560f980c0e649/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fc20894c3d21194d8041a28b65622d5b86db786da6e3cfe73f0c762951a61167", size = 2491645, upload-time = "2026-03-09T13:14:06.106Z" }, + { url = "https://files.pythonhosted.org/packages/cb/32/900647fd0840abebe1561792c6b31e6a7c0e278fc3973d30572a965ca14c/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7a32f72973f0f950c1920475d5c5ea3d971b81b6f0ec53b8d0a956cc965f22e0", size = 2295237, upload-time = "2026-03-09T13:14:08.891Z" }, + { url = "https://files.pythonhosted.org/packages/be/8a/be60e3bbcf513cc5a50f4a3e88e1dcecebb79c1ad607a7222877becaa101/kiwisolver-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bf3acf1419fa93064a4c2189ac0b58e3be7872bf6ee6177b0d4c63dc4cea276", size = 73573, upload-time = "2026-03-09T13:14:12.327Z" }, + { url = "https://files.pythonhosted.org/packages/4d/d2/64be2e429eb4fca7f7e1c52a91b12663aeaf25de3895e5cca0f47ef2a8d0/kiwisolver-1.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:fa8eb9ecdb7efb0b226acec134e0d709e87a909fa4971a54c0c4f6e88635484c", size = 64998, upload-time = "2026-03-09T13:14:13.469Z" }, + { url = "https://files.pythonhosted.org/packages/b0/69/ce68dd0c85755ae2de490bf015b62f2cea5f6b14ff00a463f9d0774449ff/kiwisolver-1.5.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:db485b3847d182b908b483b2ed133c66d88d49cacf98fd278fadafe11b4478d1", size = 125700, upload-time = "2026-03-09T13:14:14.636Z" }, + { url = "https://files.pythonhosted.org/packages/74/aa/937aac021cf9d4349990d47eb319309a51355ed1dbdc9c077cdc9224cb11/kiwisolver-1.5.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:be12f931839a3bdfe28b584db0e640a65a8bcbc24560ae3fdb025a449b3d754e", size = 67537, upload-time = "2026-03-09T13:14:15.808Z" }, + { url = "https://files.pythonhosted.org/packages/ee/20/3a87fbece2c40ad0f6f0aefa93542559159c5f99831d596050e8afae7a9f/kiwisolver-1.5.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:16b85d37c2cbb3253226d26e64663f755d88a03439a9c47df6246b35defbdfb7", size = 65514, upload-time = "2026-03-09T13:14:18.035Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7f/f943879cda9007c45e1f7dba216d705c3a18d6b35830e488b6c6a4e7cdf0/kiwisolver-1.5.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4432b835675f0ea7414aab3d37d119f7226d24869b7a829caeab49ebda407b0c", size = 1584848, upload-time = "2026-03-09T13:14:19.745Z" }, + { url = "https://files.pythonhosted.org/packages/37/f8/4d4f85cc1870c127c88d950913370dd76138482161cd07eabbc450deff01/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b0feb50971481a2cc44d94e88bdb02cdd497618252ae226b8eb1201b957e368", size = 1391542, upload-time = "2026-03-09T13:14:21.54Z" }, + { url = "https://files.pythonhosted.org/packages/04/0b/65dd2916c84d252b244bd405303220f729e7c17c9d7d33dca6feeff9ffc4/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56fa888f10d0f367155e76ce849fa1166fc9730d13bd2d65a2aa13b6f5424489", size = 1404447, upload-time = "2026-03-09T13:14:23.205Z" }, + { url = "https://files.pythonhosted.org/packages/39/5c/2606a373247babce9b1d056c03a04b65f3cf5290a8eac5d7bdead0a17e21/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:940dda65d5e764406b9fb92761cbf462e4e63f712ab60ed98f70552e496f3bf1", size = 1455918, upload-time = "2026-03-09T13:14:24.74Z" }, + { url = "https://files.pythonhosted.org/packages/d5/d1/c6078b5756670658e9192a2ef11e939c92918833d2745f85cd14a6004bdf/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_39_riscv64.whl", hash = "sha256:89fc958c702ee9a745e4700378f5d23fddbc46ff89e8fdbf5395c24d5c1452a3", size = 1072856, upload-time = "2026-03-09T13:14:26.597Z" }, + { url = "https://files.pythonhosted.org/packages/cb/c8/7def6ddf16eb2b3741d8b172bdaa9af882b03c78e9b0772975408801fa63/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9027d773c4ff81487181a925945743413f6069634d0b122d0b37684ccf4f1e18", size = 2333580, upload-time = "2026-03-09T13:14:28.237Z" }, + { url = "https://files.pythonhosted.org/packages/9e/87/2ac1fce0eb1e616fcd3c35caa23e665e9b1948bb984f4764790924594128/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:5b233ea3e165e43e35dba1d2b8ecc21cf070b45b65ae17dd2747d2713d942021", size = 2423018, upload-time = "2026-03-09T13:14:30.018Z" }, + { url = "https://files.pythonhosted.org/packages/67/13/c6700ccc6cc218716bfcda4935e4b2997039869b4ad8a94f364c5a3b8e63/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ce9bf03dad3b46408c08649c6fbd6ca28a9fce0eb32fdfffa6775a13103b5310", size = 2062804, upload-time = "2026-03-09T13:14:32.888Z" }, + { url = "https://files.pythonhosted.org/packages/1b/bd/877056304626943ff0f1f44c08f584300c199b887cb3176cd7e34f1515f1/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:fc4d3f1fb9ca0ae9f97b095963bc6326f1dbfd3779d6679a1e016b9baaa153d3", size = 2597482, upload-time = "2026-03-09T13:14:34.971Z" }, + { url = "https://files.pythonhosted.org/packages/75/19/c60626c47bf0f8ac5dcf72c6c98e266d714f2fbbfd50cf6dab5ede3aaa50/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f443b4825c50a51ee68585522ab4a1d1257fac65896f282b4c6763337ac9f5d2", size = 2394328, upload-time = "2026-03-09T13:14:36.816Z" }, + { url = "https://files.pythonhosted.org/packages/47/84/6a6d5e5bb8273756c27b7d810d47f7ef2f1f9b9fd23c9ee9a3f8c75c9cef/kiwisolver-1.5.0-cp313-cp313t-win_arm64.whl", hash = "sha256:893ff3a711d1b515ba9da14ee090519bad4610ed1962fbe298a434e8c5f8db53", size = 68410, upload-time = "2026-03-09T13:14:38.695Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/060f45052f2a01ad5762c8fdecd6d7a752b43400dc29ff75cd47225a40fd/kiwisolver-1.5.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8df31fe574b8b3993cc61764f40941111b25c2d9fea13d3ce24a49907cd2d615", size = 123231, upload-time = "2026-03-09T13:14:41.323Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a7/78da680eadd06ff35edef6ef68a1ad273bad3e2a0936c9a885103230aece/kiwisolver-1.5.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1d49a49ac4cbfb7c1375301cd1ec90169dfeae55ff84710d782260ce77a75a02", size = 66489, upload-time = "2026-03-09T13:14:42.534Z" }, + { url = "https://files.pythonhosted.org/packages/49/b2/97980f3ad4fae37dd7fe31626e2bf75fbf8bdf5d303950ec1fab39a12da8/kiwisolver-1.5.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0cbe94b69b819209a62cb27bdfa5dc2a8977d8de2f89dfd97ba4f53ed3af754e", size = 64063, upload-time = "2026-03-09T13:14:44.759Z" }, + { url = "https://files.pythonhosted.org/packages/e7/f9/b06c934a6aa8bc91f566bd2a214fd04c30506c2d9e2b6b171953216a65b6/kiwisolver-1.5.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:80aa065ffd378ff784822a6d7c3212f2d5f5e9c3589614b5c228b311fd3063ac", size = 1475913, upload-time = "2026-03-09T13:14:46.247Z" }, + { url = "https://files.pythonhosted.org/packages/6b/f0/f768ae564a710135630672981231320bc403cf9152b5596ec5289de0f106/kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e7f886f47ab881692f278ae901039a234e4025a68e6dfab514263a0b1c4ae05", size = 1282782, upload-time = "2026-03-09T13:14:48.458Z" }, + { url = "https://files.pythonhosted.org/packages/e2/9f/1de7aad00697325f05238a5f2eafbd487fb637cc27a558b5367a5f37fb7f/kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5060731cc3ed12ca3a8b57acd4aeca5bbc2f49216dd0bec1650a1acd89486bcd", size = 1300815, upload-time = "2026-03-09T13:14:50.721Z" }, + { url = "https://files.pythonhosted.org/packages/5a/c2/297f25141d2e468e0ce7f7a7b92e0cf8918143a0cbd3422c1ad627e85a06/kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7a4aa69609f40fce3cbc3f87b2061f042eee32f94b8f11db707b66a26461591a", size = 1347925, upload-time = "2026-03-09T13:14:52.304Z" }, + { url = "https://files.pythonhosted.org/packages/b9/d3/f4c73a02eb41520c47610207b21afa8cdd18fdbf64ffd94674ae21c4812d/kiwisolver-1.5.0-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:d168fda2dbff7b9b5f38e693182d792a938c31db4dac3a80a4888de603c99554", size = 991322, upload-time = "2026-03-09T13:14:54.637Z" }, + { url = "https://files.pythonhosted.org/packages/7b/46/d3f2efef7732fcda98d22bf4ad5d3d71d545167a852ca710a494f4c15343/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:413b820229730d358efd838ecbab79902fe97094565fdc80ddb6b0a18c18a581", size = 2232857, upload-time = "2026-03-09T13:14:56.471Z" }, + { url = "https://files.pythonhosted.org/packages/3f/ec/2d9756bf2b6d26ae4349b8d3662fb3993f16d80c1f971c179ce862b9dbae/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5124d1ea754509b09e53738ec185584cc609aae4a3b510aaf4ed6aa047ef9303", size = 2329376, upload-time = "2026-03-09T13:14:58.072Z" }, + { url = "https://files.pythonhosted.org/packages/8f/9f/876a0a0f2260f1bde92e002b3019a5fabc35e0939c7d945e0fa66185eb20/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e4415a8db000bf49a6dd1c478bf70062eaacff0f462b92b0ba68791a905861f9", size = 1982549, upload-time = "2026-03-09T13:14:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/6c/4f/ba3624dfac23a64d54ac4179832860cb537c1b0af06024936e82ca4154a0/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d618fd27420381a4f6044faa71f46d8bfd911bd077c555f7138ed88729bfbe79", size = 2494680, upload-time = "2026-03-09T13:15:01.364Z" }, + { url = "https://files.pythonhosted.org/packages/39/b7/97716b190ab98911b20d10bf92eca469121ec483b8ce0edd314f51bc85af/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5092eb5b1172947f57d6ea7d89b2f29650414e4293c47707eb499ec07a0ac796", size = 2297905, upload-time = "2026-03-09T13:15:03.925Z" }, + { url = "https://files.pythonhosted.org/packages/a3/36/4e551e8aa55c9188bca9abb5096805edbf7431072b76e2298e34fd3a3008/kiwisolver-1.5.0-cp314-cp314-win_amd64.whl", hash = "sha256:d76e2d8c75051d58177e762164d2e9ab92886534e3a12e795f103524f221dd8e", size = 75086, upload-time = "2026-03-09T13:15:07.775Z" }, + { url = "https://files.pythonhosted.org/packages/70/15/9b90f7df0e31a003c71649cf66ef61c3c1b862f48c81007fa2383c8bd8d7/kiwisolver-1.5.0-cp314-cp314-win_arm64.whl", hash = "sha256:fa6248cd194edff41d7ea9425ced8ca3a6f838bfb295f6f1d6e6bb694a8518df", size = 66577, upload-time = "2026-03-09T13:15:09.139Z" }, + { url = "https://files.pythonhosted.org/packages/17/01/7dc8c5443ff42b38e72731643ed7cf1ed9bf01691ae5cdca98501999ed83/kiwisolver-1.5.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:d1ffeb80b5676463d7a7d56acbe8e37a20ce725570e09549fe738e02ca6b7e1e", size = 125794, upload-time = "2026-03-09T13:15:10.525Z" }, + { url = "https://files.pythonhosted.org/packages/46/8a/b4ebe46ebaac6a303417fab10c2e165c557ddaff558f9699d302b256bc53/kiwisolver-1.5.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:bc4d8e252f532ab46a1de9349e2d27b91fce46736a9eedaa37beaca66f574ed4", size = 67646, upload-time = "2026-03-09T13:15:12.016Z" }, + { url = "https://files.pythonhosted.org/packages/60/35/10a844afc5f19d6f567359bf4789e26661755a2f36200d5d1ed8ad0126e5/kiwisolver-1.5.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6783e069732715ad0c3ce96dbf21dbc2235ab0593f2baf6338101f70371f4028", size = 65511, upload-time = "2026-03-09T13:15:13.311Z" }, + { url = "https://files.pythonhosted.org/packages/f8/8a/685b297052dd041dcebce8e8787b58923b6e78acc6115a0dc9189011c44b/kiwisolver-1.5.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e7c4c09a490dc4d4a7f8cbee56c606a320f9dc28cf92a7157a39d1ce7676a657", size = 1584858, upload-time = "2026-03-09T13:15:15.103Z" }, + { url = "https://files.pythonhosted.org/packages/9e/80/04865e3d4638ac5bddec28908916df4a3075b8c6cc101786a96803188b96/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a075bd7bd19c70cf67c8badfa36cf7c5d8de3c9ddb8420c51e10d9c50e94920", size = 1392539, upload-time = "2026-03-09T13:15:16.661Z" }, + { url = "https://files.pythonhosted.org/packages/ba/01/77a19cacc0893fa13fafa46d1bba06fb4dc2360b3292baf4b56d8e067b24/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bdd3e53429ff02aa319ba59dfe4ceeec345bf46cf180ec2cf6fd5b942e7975e9", size = 1405310, upload-time = "2026-03-09T13:15:18.229Z" }, + { url = "https://files.pythonhosted.org/packages/53/39/bcaf5d0cca50e604cfa9b4e3ae1d64b50ca1ae5b754122396084599ef903/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cdcb35dc9d807259c981a85531048ede628eabcffb3239adf3d17463518992d", size = 1456244, upload-time = "2026-03-09T13:15:20.444Z" }, + { url = "https://files.pythonhosted.org/packages/d0/7a/72c187abc6975f6978c3e39b7cf67aeb8b3c0a8f9790aa7fd412855e9e1f/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:70d593af6a6ca332d1df73d519fddb5148edb15cd90d5f0155e3746a6d4fcc65", size = 1073154, upload-time = "2026-03-09T13:15:22.039Z" }, + { url = "https://files.pythonhosted.org/packages/c7/ca/cf5b25783ebbd59143b4371ed0c8428a278abe68d6d0104b01865b1bbd0f/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:377815a8616074cabbf3f53354e1d040c35815a134e01d7614b7692e4bf8acfa", size = 2334377, upload-time = "2026-03-09T13:15:23.741Z" }, + { url = "https://files.pythonhosted.org/packages/4a/e5/b1f492adc516796e88751282276745340e2a72dcd0d36cf7173e0daf3210/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0255a027391d52944eae1dbb5d4cc5903f57092f3674e8e544cdd2622826b3f0", size = 2425288, upload-time = "2026-03-09T13:15:25.789Z" }, + { url = "https://files.pythonhosted.org/packages/e6/e5/9b21fbe91a61b8f409d74a26498706e97a48008bfcd1864373d32a6ba31c/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:012b1eb16e28718fa782b5e61dc6f2da1f0792ca73bd05d54de6cb9561665fc9", size = 2063158, upload-time = "2026-03-09T13:15:27.63Z" }, + { url = "https://files.pythonhosted.org/packages/b1/02/83f47986138310f95ea95531f851b2a62227c11cbc3e690ae1374fe49f0f/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0e3aafb33aed7479377e5e9a82e9d4bf87063741fc99fc7ae48b0f16e32bdd6f", size = 2597260, upload-time = "2026-03-09T13:15:29.421Z" }, + { url = "https://files.pythonhosted.org/packages/07/18/43a5f24608d8c313dd189cf838c8e68d75b115567c6279de7796197cfb6a/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e7a116ae737f0000343218c4edf5bd45893bfeaff0993c0b215d7124c9f77646", size = 2394403, upload-time = "2026-03-09T13:15:31.517Z" }, + { url = "https://files.pythonhosted.org/packages/3b/b5/98222136d839b8afabcaa943b09bd05888c2d36355b7e448550211d1fca4/kiwisolver-1.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:1dd9b0b119a350976a6d781e7278ec7aca0b201e1a9e2d23d9804afecb6ca681", size = 79687, upload-time = "2026-03-09T13:15:33.204Z" }, + { url = "https://files.pythonhosted.org/packages/99/a2/ca7dc962848040befed12732dff6acae7fb3c4f6fc4272b3f6c9a30b8713/kiwisolver-1.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:58f812017cd2985c21fbffb4864d59174d4903dd66fa23815e74bbc7a0e2dd57", size = 70032, upload-time = "2026-03-09T13:15:34.411Z" }, + { url = "https://files.pythonhosted.org/packages/1c/fa/2910df836372d8761bb6eff7d8bdcb1613b5c2e03f260efe7abe34d388a7/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_10_13_x86_64.whl", hash = "sha256:5ae8e62c147495b01a0f4765c878e9bfdf843412446a247e28df59936e99e797", size = 130262, upload-time = "2026-03-09T13:15:35.629Z" }, + { url = "https://files.pythonhosted.org/packages/0f/41/c5f71f9f00aabcc71fee8b7475e3f64747282580c2fe748961ba29b18385/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f6764a4ccab3078db14a632420930f6186058750df066b8ea2a7106df91d3203", size = 138036, upload-time = "2026-03-09T13:15:36.894Z" }, + { url = "https://files.pythonhosted.org/packages/fa/06/7399a607f434119c6e1fdc8ec89a8d51ccccadf3341dee4ead6bd14caaf5/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c31c13da98624f957b0fb1b5bae5383b2333c2c3f6793d9825dd5ce79b525cb7", size = 194295, upload-time = "2026-03-09T13:15:38.22Z" }, + { url = "https://files.pythonhosted.org/packages/b5/91/53255615acd2a1eaca307ede3c90eb550bae9c94581f8c00081b6b1c8f44/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-win_amd64.whl", hash = "sha256:1f1489f769582498610e015a8ef2d36f28f505ab3096d0e16b4858a9ec214f57", size = 75987, upload-time = "2026-03-09T13:15:39.65Z" }, + { url = "https://files.pythonhosted.org/packages/e9/eb/5fcbbbf9a0e2c3a35effb88831a483345326bbc3a030a3b5b69aee647f84/kiwisolver-1.5.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ec4c85dc4b687c7f7f15f553ff26a98bfe8c58f5f7f0ac8905f0ba4c7be60232", size = 59532, upload-time = "2026-03-09T13:15:47.047Z" }, + { url = "https://files.pythonhosted.org/packages/c3/9b/e17104555bb4db148fd52327feea1e96be4b88e8e008b029002c281a21ab/kiwisolver-1.5.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:12e91c215a96e39f57989c8912ae761286ac5a9584d04030ceb3368a357f017a", size = 57420, upload-time = "2026-03-09T13:15:48.199Z" }, + { url = "https://files.pythonhosted.org/packages/48/44/2b5b95b7aa39fb2d8d9d956e0f3d5d45aef2ae1d942d4c3ffac2f9cfed1a/kiwisolver-1.5.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:be4a51a55833dc29ab5d7503e7bcb3b3af3402d266018137127450005cdfe737", size = 79892, upload-time = "2026-03-09T13:15:49.694Z" }, + { url = "https://files.pythonhosted.org/packages/52/7d/7157f9bba6b455cfb4632ed411e199fc8b8977642c2b12082e1bd9e6d173/kiwisolver-1.5.0-pp311-pypy311_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:daae526907e262de627d8f70058a0f64acc9e2641c164c99c8f594b34a799a16", size = 77603, upload-time = "2026-03-09T13:15:50.945Z" }, + { url = "https://files.pythonhosted.org/packages/0a/dd/8050c947d435c8d4bc94e3252f4d8bb8a76cfb424f043a8680be637a57f1/kiwisolver-1.5.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:59cd8683f575d96df5bb48f6add94afc055012c29e28124fcae2b63661b9efb1", size = 73558, upload-time = "2026-03-09T13:15:52.112Z" }, +] + +[[package]] +name = "librt" +version = "0.11.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/40/08/9e7f6b5d2b5bed6ad055cdd5925f192bb403a51280f86b56554d9d0699a2/librt-0.11.0.tar.gz", hash = "sha256:075dc3ef4458a278e0195cbf6ac9d38808d9b906c5a6c7f7f79c3888276a3fb1", size = 200139, upload-time = "2026-05-10T18:17:25.138Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/87/2bf31fe17587b29e3f93ec31421e2b1e1c3e349b8bf6c7c313dbad1d5340/librt-0.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:93d95bd45b7d58343d8b90d904450a545144eec19a002511163426f8ab1fae29", size = 141092, upload-time = "2026-05-10T18:15:34.795Z" }, + { url = "https://files.pythonhosted.org/packages/cf/08/5c5bf772920b7ebac6e32bc91a643e0ab3870199c0b542356d3baa83970a/librt-0.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ee278c769a713638cdacd4c0436d72156e75df3ebc0166ab2b9dc43acc386c9", size = 142035, upload-time = "2026-05-10T18:15:36.242Z" }, + { url = "https://files.pythonhosted.org/packages/06/20/662a03d254e5b000d838e8b345d83303ddb768c080fd488e40634c0fa66b/librt-0.11.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f230cb1cbc9faaa616f9a678f530ebcf186e414b6bcbd88b960e4ba1b92428d5", size = 475022, upload-time = "2026-05-10T18:15:37.56Z" }, + { url = "https://files.pythonhosted.org/packages/de/f3/aa81523e45184c6ec23dc7f63263362ec55f80a09d424c012359ecbe7e35/librt-0.11.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:5d63c855d86938d9de93e265c9bd8c705b51ec494de5738340ee93767a686e4b", size = 467273, upload-time = "2026-05-10T18:15:39.182Z" }, + { url = "https://files.pythonhosted.org/packages/6b/6f/59c74b560ca8853834d5501d589c8a2519f4184f273a085ffd0f37a1cc47/librt-0.11.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:993f028be9e96a08d31df3479ac80d99be374d17f3b78e4796b3fd3c913d4e89", size = 497083, upload-time = "2026-05-10T18:15:40.634Z" }, + { url = "https://files.pythonhosted.org/packages/fe/7b/5aa4d2c9600a719401160bf7055417df0b2a47439b9d88286ce45e56b65f/librt-0.11.0-cp311-cp311-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:258d73a0aa66a055e65b2e4d1b8cdb23b9d132c5bb915d9547d804fcaed116cc", size = 489139, upload-time = "2026-05-10T18:15:41.934Z" }, + { url = "https://files.pythonhosted.org/packages/d6/31/9143803d7da6856a69153785768c4936864430eec0fd9461c3ea527d9922/librt-0.11.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0827efe7854718f04aaddf6496e96960a956e676fe1d0f04eb41511fd8ad06d5", size = 508442, upload-time = "2026-05-10T18:15:43.206Z" }, + { url = "https://files.pythonhosted.org/packages/2f/5a/bce08184488426bda4ccc2c4964ac048c8f68ae89bd7120082eef4233cfd/librt-0.11.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7753e57d6e12d019c0d8786f1c09c709f4c3fcc57c3887b24e36e6c06ec938b7", size = 514230, upload-time = "2026-05-10T18:15:44.761Z" }, + { url = "https://files.pythonhosted.org/packages/89/8c/bb5e213d254b7505a0e658da199d8ab719086632ce09eef311ab27976523/librt-0.11.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:11bd19822431cc21af9f27374e7ae2e58103c7d98bda823536a6c47f6bb2bb3d", size = 494231, upload-time = "2026-05-10T18:15:46.308Z" }, + { url = "https://files.pythonhosted.org/packages/9d/fb/541cdad5b1ab1300398c74c4c9a497b88e5074c21b1244c8f49731d3a284/librt-0.11.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:22bdf239b219d3993761a148ffa134b19e52e9989c84f845d5d7b71d70a17412", size = 537585, upload-time = "2026-05-10T18:15:47.629Z" }, + { url = "https://files.pythonhosted.org/packages/8f/f2/464bb69295c320cb06bddb4f14a4ec67934ee14b2bffb12b19fb7ab287ba/librt-0.11.0-cp311-cp311-win32.whl", hash = "sha256:46c60b61e308eb535fbd6fa622b1ee1bb2815691c1ad9c98bf7b84952ec3bc8d", size = 100509, upload-time = "2026-05-10T18:15:49.157Z" }, + { url = "https://files.pythonhosted.org/packages/6d/e7/a17ee1788f9e4fbf548c19f4afa07c92089b9e24fef6cb2410863781ef4c/librt-0.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:902e546ff044f579ff1c953ff5fce97b636fe9e3943996b2177710c6ef076f73", size = 118628, upload-time = "2026-05-10T18:15:50.345Z" }, + { url = "https://files.pythonhosted.org/packages/cc/c7/6c766214f9f9903bcfcfbef97d807af8d8f5aa3502d247858ab17582d212/librt-0.11.0-cp311-cp311-win_arm64.whl", hash = "sha256:65ac3bc20f78aa0ee5ae84baa68917f89fef4af63e941084dd019a0d0e749f0c", size = 103122, upload-time = "2026-05-10T18:15:52.068Z" }, + { url = "https://files.pythonhosted.org/packages/8b/d0/07c77e067f0838949b43bd89232c29d72efebb9d2801a9750184eb706b71/librt-0.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b87504f1690a23b9a2cca841191a04f83895d4fc2dd04df91d82b1a04ca2ad46", size = 144147, upload-time = "2026-05-10T18:15:53.227Z" }, + { url = "https://files.pythonhosted.org/packages/7a/24/8493538fa4f62f982686398a5b8f68008138a75086abdea19ade64bf4255/librt-0.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40071fc5fe0ce8daa6de616702314a01e1250711682b0523d6ab8d4525910cb3", size = 143614, upload-time = "2026-05-10T18:15:54.657Z" }, + { url = "https://files.pythonhosted.org/packages/ff/1e/f8bad050810d9171f34a1648ed910e56814c2ba61639f2bd53c6377ae24b/librt-0.11.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:137e79445c896a0ea7b265f52d23954e05b64222ee1af69e2cb34219067cbb67", size = 485538, upload-time = "2026-05-10T18:15:56.117Z" }, + { url = "https://files.pythonhosted.org/packages/c0/fe/3594ebfbaf03084ba4b120c9ba5c3183fd938a48725e9bbe6ff0a5159ad8/librt-0.11.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:cca6644054e78746d8d4ef238681f9c34ff8b584fe6b988ecebb8db3b15e622a", size = 479623, upload-time = "2026-05-10T18:15:57.544Z" }, + { url = "https://files.pythonhosted.org/packages/b0/da/5d1876984b3746c85dbd219dbfcb73c85f54ee263fd32e5b2a632ec14571/librt-0.11.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5b0eea49f5562861ee8d757a32ef7d559c1d35be2aaaa1ec28941d74c9ffc8a", size = 513082, upload-time = "2026-05-10T18:15:58.805Z" }, + { url = "https://files.pythonhosted.org/packages/19/6e/55bdf5d5ca00c3e18430690bf2c953d8d3ffd3c337418173d33dec985dc9/librt-0.11.0-cp312-cp312-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0d1029d7e1ae1a7e647ed6fb5df8c4ce2dffefb7a9f5fd1376a4554d96dac09f", size = 508105, upload-time = "2026-05-10T18:16:00.2Z" }, + { url = "https://files.pythonhosted.org/packages/07/10/f1f23a7c595ee90ece4d35c851e5d104b1311a887ed1b4ac4c35bbd13da8/librt-0.11.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bc3ce6b33c5828d9e80592011a5c584cb2ce86edbc4088405f70da47dc1d1b3b", size = 522268, upload-time = "2026-05-10T18:16:01.708Z" }, + { url = "https://files.pythonhosted.org/packages/b6/02/5720f5697a7f54b78b3aefbe20df3a48cedcff1276618c4aa481177942ed/librt-0.11.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:936c5995f3514a42111f20099397d8177c79b4d7e70961e396c6f5a0a3566766", size = 527348, upload-time = "2026-05-10T18:16:03.496Z" }, + { url = "https://files.pythonhosted.org/packages/50/db/b4a47c6f91db4ff76348a0b3dd0cc65e090a078b765a810a62ff9434c3d3/librt-0.11.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:9bc0ca6ad9381cbe8e4aa6e5726e4c80c78115a6e9723c599ed1d73e092bc49d", size = 516294, upload-time = "2026-05-10T18:16:05.173Z" }, + { url = "https://files.pythonhosted.org/packages/9e/58/9384b2f4eb1ed1d273d40948a7c5c4b2360213b402ef3be4641c06299f9c/librt-0.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:070aa8c26c0a74774317a72df8851facc7f0f012a5b406557ac56992d92e1ec8", size = 553608, upload-time = "2026-05-10T18:16:06.839Z" }, + { url = "https://files.pythonhosted.org/packages/21/7b/5aa8848a7c6a9278c79375146da1812e695754ceec5f005e6043461a7315/librt-0.11.0-cp312-cp312-win32.whl", hash = "sha256:6bf14feb84b05ae945277395451998c89c54d0def4070eb5c08de544930b245a", size = 101879, upload-time = "2026-05-10T18:16:08.103Z" }, + { url = "https://files.pythonhosted.org/packages/37/33/8a745436944947575b584231750a41417de1a38cf6a2e9251d1065651c09/librt-0.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:75672f0bc524ede266287d532d7923dbce94c7514ad07627bac3d0c6d92cc4d9", size = 119831, upload-time = "2026-05-10T18:16:09.174Z" }, + { url = "https://files.pythonhosted.org/packages/59/67/a6739ac96e28b7855808bdb0370e250606104a859750d209e5a0716fe7ab/librt-0.11.0-cp312-cp312-win_arm64.whl", hash = "sha256:2f10cf143e4a9bb0f4f5af568a00df94a2d69ef41c2579584454bb0fe5cc642c", size = 103470, upload-time = "2026-05-10T18:16:10.369Z" }, + { url = "https://files.pythonhosted.org/packages/82/61/e59168d4d0bf2bf90f4f0caf7a001bfc60254c3af4586013b04dc3ef517b/librt-0.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:78dc31f7fdfe9c9d0eb0e8f42d139db230e826415bbcabd9f0e9faaaee909894", size = 144119, upload-time = "2026-05-10T18:16:11.771Z" }, + { url = "https://files.pythonhosted.org/packages/61/fd/caa1d60b12f7dd79ccea23054e06eeaebe266a5f52c40a6b651069200ce5/librt-0.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fa475675db22290c3158e1d42326d0f5a65f04f44a0e68c3630a25b53560fb9c", size = 143565, upload-time = "2026-05-10T18:16:13.334Z" }, + { url = "https://files.pythonhosted.org/packages/b8/a9/dc744f5c2b4978d48db970be29f22716d3413d28b14ad99740817315cf2c/librt-0.11.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:621db29691044bdeda22e789e482e1b0f3a985d90e3426c9c6d17606416205ea", size = 485395, upload-time = "2026-05-10T18:16:14.729Z" }, + { url = "https://files.pythonhosted.org/packages/8f/21/7f8e97a1e4dae952a5a95948f6f8507a173bc1e669f54340bba6ca1ca31b/librt-0.11.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:a9010e2ed5b3a9e158c5fd966b3ab7e834bb3d3aacc8f66c91dd4b57a3799230", size = 479383, upload-time = "2026-05-10T18:16:16.321Z" }, + { url = "https://files.pythonhosted.org/packages/a6/6d/d8ee9c114bebf2c50e29ec2aa940826fccb62a645c3e4c18760987d0e16d/librt-0.11.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c39513d8b7477a2e1ed8c43fc21c524e8d5a0f8d4e8b7b074dbdbe7820a08e2", size = 513010, upload-time = "2026-05-10T18:16:17.647Z" }, + { url = "https://files.pythonhosted.org/packages/f0/43/0b5708af2bd30a46400e72ba6bdaa8f066f15fb9a688527e34220e8d6c06/librt-0.11.0-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7aef3cf1d5af86e770ab04bfd993dfc4ae8b8c17f66fb77dd4a7d50de7bbb1a3", size = 508433, upload-time = "2026-05-10T18:16:19.309Z" }, + { url = "https://files.pythonhosted.org/packages/4a/50/356187247d09013490481033183b3532b58acf8028bcb34b2b56a375c9b2/librt-0.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:557183ddc36babe46b27dd60facbd5adb4492181a5be887587d57cda6e092f21", size = 522595, upload-time = "2026-05-10T18:16:20.642Z" }, + { url = "https://files.pythonhosted.org/packages/40/e7/c6ac4240899c7f3248079d5a9900debe0dadb3fdeaf856684c987105ba47/librt-0.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:83d3e1f72bd42f6c5c0b7daec530c3f829bd02db42c70b8ddf0c2d90a2459930", size = 527255, upload-time = "2026-05-10T18:16:22.352Z" }, + { url = "https://files.pythonhosted.org/packages/eb/b5/a81322dbeedeeaf9c1ee6f001734d28a09d8383ac9e6779bc24bbd0743c6/librt-0.11.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:4ce1f21fbe589bc1afd7872dece84fb0e1144f794a288e58a10d2c54a55c43be", size = 516847, upload-time = "2026-05-10T18:16:23.627Z" }, + { url = "https://files.pythonhosted.org/packages/ae/66/6e6323787d592b55204a42595ff1102da5115601b53a7e9ddebc889a6da5/librt-0.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:970b09f7044ea2b64c9da42fd3d335666518cfd1c6e8a182c95da73d0214b41e", size = 553920, upload-time = "2026-05-10T18:16:25.025Z" }, + { url = "https://files.pythonhosted.org/packages/9c/21/623f8ca230857102066d9ca8c6c1734995908c4d0d1bee7bb2ef0021cb33/librt-0.11.0-cp313-cp313-win32.whl", hash = "sha256:78fddc31cd4d3caa897ad5d31f856b1faadc9474021ad6cb182b9018793e254e", size = 101898, upload-time = "2026-05-10T18:16:26.649Z" }, + { url = "https://files.pythonhosted.org/packages/b3/1d/b4ebd44dd723f768469007515cb92251e0ae286c94c140f374801140fa74/librt-0.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ca8aa88751a775870b764e93bad5135385f563cb8dcee399abf034ea4d3cb47", size = 119812, upload-time = "2026-05-10T18:16:27.859Z" }, + { url = "https://files.pythonhosted.org/packages/3b/e4/b2f4ca7965ca373b491cdb4bc25cdb30c1649ca81a8782056a83850292a9/librt-0.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:96f044bb325fd9cf1a723015638c219e9143f0dfbc0ca54c565df2b7fc748b44", size = 103448, upload-time = "2026-05-10T18:16:29.066Z" }, + { url = "https://files.pythonhosted.org/packages/29/eb/dbce197da4e227779e56b5735f2decc3eb36e55a1cdbf1bd65d6639d76c1/librt-0.11.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4a017a95e5837dc15a8c5661d60e05daa96b90908b1aa6b7acdf443cd25c8ebd", size = 143345, upload-time = "2026-05-10T18:16:30.674Z" }, + { url = "https://files.pythonhosted.org/packages/76/a3/254bebd0c11c8ba684018efb8006ff22e466abce445215cca6c778e7d9de/librt-0.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b1ecbd9819deccc39b7542bf4d2a740d8a620694d39989e58661d3763458f8d4", size = 143131, upload-time = "2026-05-10T18:16:32.037Z" }, + { url = "https://files.pythonhosted.org/packages/f1/3f/f77d6122d21ac7bf6ae8a7dfced1bd2a7ac545d3273ebdcaf8042f6d619f/librt-0.11.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7da327dacd7be8f8ec36547373550744a3cc0e536d54665cd83f8bcd961200e8", size = 477024, upload-time = "2026-05-10T18:16:33.493Z" }, + { url = "https://files.pythonhosted.org/packages/ac/0a/2c996dadebaa7d9bbbd43ef2d4f3e66b6da545f838a41694ef6172cebec8/librt-0.11.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:0dc56b1f8d06e60db362cc3fdae206681817f86ce4725d34511473487f12a34b", size = 474221, upload-time = "2026-05-10T18:16:34.864Z" }, + { url = "https://files.pythonhosted.org/packages/0a/7e/f5d92af8486b8272c23b3e686b46ff72d89c8169585eb61eef01a2ac7147/librt-0.11.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05fb8fb2ab90e21c8d12ea240d744ad514da9baf381ebfa70d91d20d21713175", size = 505174, upload-time = "2026-05-10T18:16:36.705Z" }, + { url = "https://files.pythonhosted.org/packages/af/1a/cb0734fe86398eb33193ab753b7326255c74cac5eb09e76b9b16536e7adb/librt-0.11.0-cp314-cp314-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cae74872be221df4374d10fec61f93ed1513b9546ea84f2c0bf73ab3e9bd0b03", size = 497216, upload-time = "2026-05-10T18:16:38.418Z" }, + { url = "https://files.pythonhosted.org/packages/18/06/094820f91558b66e29943c0ec41c9914f460f48dd51fc503c3101e10842d/librt-0.11.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:32bcc918c0148eb7e3d57385125bac7e5f9e4359d05f07448b09f6f778c2f31c", size = 513921, upload-time = "2026-05-10T18:16:39.848Z" }, + { url = "https://files.pythonhosted.org/packages/0b/c2/00de9018871a282f530cacb457d5ec0428f6ac7e6fedde9aff7468d9fb04/librt-0.11.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:f9743fc99135d5f78d2454435615f6dec0473ca507c26ce9d92b10b562a280d3", size = 520850, upload-time = "2026-05-10T18:16:41.471Z" }, + { url = "https://files.pythonhosted.org/packages/51/9d/64631832348fd1834fb3a61b996434edddaaf25a31d03b0a76273159d2cf/librt-0.11.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:5ba067f4aadae8fda802d91d2124c90c42195ff32d9161d3549e6d05cfe26f96", size = 504237, upload-time = "2026-05-10T18:16:43.15Z" }, + { url = "https://files.pythonhosted.org/packages/a5/ec/ae5525eb16edc827a044e7bb8777a455ff95d4bca9379e7e6bddd7383647/librt-0.11.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:de3bf945454d032f9e390b85c4072e0a0570bf825421c8be0e71209fa65e1abe", size = 546261, upload-time = "2026-05-10T18:16:44.408Z" }, + { url = "https://files.pythonhosted.org/packages/5a/09/adce371f27ca039411da9659f7430fcc2ba6cd0c7b3e4467a0f091be7fa9/librt-0.11.0-cp314-cp314-win32.whl", hash = "sha256:d2277a05f6dcb9fd13db9566aac4fabd68c3ea1ea46ee5567d4eef8efa495a2f", size = 96965, upload-time = "2026-05-10T18:16:46.039Z" }, + { url = "https://files.pythonhosted.org/packages/d6/ee/8ac720d98548f173c7ce2e632a7ca94673f74cacd5c8162a84af5b35958a/librt-0.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:ab73e8db5e3f564d812c1f5c3a175930a5f9bc96ccb5e3b22a34d7858b401cf7", size = 115151, upload-time = "2026-05-10T18:16:47.133Z" }, + { url = "https://files.pythonhosted.org/packages/94/20/c900cf14efeb09b6bef2b2dff20779f73464b97fd58d1c6bccc379588ae3/librt-0.11.0-cp314-cp314-win_arm64.whl", hash = "sha256:aea3caa317752e3a466fa8af45d91ee0ea8c7fdd96e42b0a8dd9b76a7931eba1", size = 98850, upload-time = "2026-05-10T18:16:48.597Z" }, + { url = "https://files.pythonhosted.org/packages/0c/71/944bfe4b64e12abffcd3c15e1cce07f72f3d55655083786285f4dedeb532/librt-0.11.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d1b36540d7aaf9b9101b3a6f376c8d8e9f7a9aec93ed05918f2c69d493ffef72", size = 151138, upload-time = "2026-05-10T18:16:49.839Z" }, + { url = "https://files.pythonhosted.org/packages/b6/10/99e64a5c86989357fda078c8143c533389585f6473b7439172dd8f3b3b2d/librt-0.11.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:efbb343ab2ce3540f4ecbe6315d677ed70f37cd9a72b1e58066c918ca83acbaa", size = 151976, upload-time = "2026-05-10T18:16:51.062Z" }, + { url = "https://files.pythonhosted.org/packages/21/31/5072ad880946d83e5ea4147d6d018c78eefce85b77819b19bdd0ee229435/librt-0.11.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa0dd688aab3f7914d3e6e5e3554978e0383312fb8e771d84be008a35b9ee548", size = 557927, upload-time = "2026-05-10T18:16:52.632Z" }, + { url = "https://files.pythonhosted.org/packages/5e/8d/70b5fb7cfbab60edbe7381614ab985da58e144fbf465c86d44c95f43cdca/librt-0.11.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:f5fb36b8c6c63fdcbb1d526d94c0d1331610d43f4118cc1beb4efef4f3faacb2", size = 539698, upload-time = "2026-05-10T18:16:53.934Z" }, + { url = "https://files.pythonhosted.org/packages/fa/a3/ba3495a0b3edbd24a4cae0d1d3c64f39a9fc45d06e812101289b50c1a619/librt-0.11.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4a9a237d13addb93715b6fee74023d5ee3469b53fce527626c0e088aa585805f", size = 577162, upload-time = "2026-05-10T18:16:55.589Z" }, + { url = "https://files.pythonhosted.org/packages/f7/db/36e25fb81f99937ff1b96612a1dc9fd66f039cb9cc3aee12c01fac31aab9/librt-0.11.0-cp314-cp314t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5ddd17bd87b2c56ddd60e546a7984a2e64c4e8eab92fb4cf3830a48ad5469d51", size = 566494, upload-time = "2026-05-10T18:16:56.975Z" }, + { url = "https://files.pythonhosted.org/packages/33/0d/3f622b47f0b013eeb9cf4cc07ae9bfe378d832a4eec998b2b209fe84244d/librt-0.11.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bd43992b4473d42f12ff9e68326079f0696d9d4e6000e8f39a0238d482ba6ee2", size = 596858, upload-time = "2026-05-10T18:16:58.374Z" }, + { url = "https://files.pythonhosted.org/packages/a9/02/71b90bc93039c46a2000651f6ad60122b114c8f54c4ad306e0e96f5b75ad/librt-0.11.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:f8e3e8056dd674e279741485e2e512d6e9a751c7455809d0114e6ebf8d781085", size = 590318, upload-time = "2026-05-10T18:16:59.676Z" }, + { url = "https://files.pythonhosted.org/packages/04/04/418cb3f75621e2b761fb1ab0f017f4d70a1a72a6e7c74ee4f7e8d198c2f3/librt-0.11.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c1f708d8ae9c56cf38a903c44297243d2ec83fd82b396b977e0144a3e76217e3", size = 575115, upload-time = "2026-05-10T18:17:01.007Z" }, + { url = "https://files.pythonhosted.org/packages/cc/2c/5a2183ac58dd911f26b5d7e7d7d8f1d87fcecdddd99d6c12169a258ff62c/librt-0.11.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0add982e0e7b9fc14cf4b33789d5f13f66581889b88c2f58099f6ce8f92617bd", size = 617918, upload-time = "2026-05-10T18:17:02.682Z" }, + { url = "https://files.pythonhosted.org/packages/15/1f/dc6771a52592a4451be6effa200cbfc9cec61e4393d3033d81a9d307961d/librt-0.11.0-cp314-cp314t-win32.whl", hash = "sha256:2b481d846ac894c4e8403c5fd0e87c5d11d6499e404b474602508a224ff531c8", size = 103562, upload-time = "2026-05-10T18:17:03.99Z" }, + { url = "https://files.pythonhosted.org/packages/62/4a/7d1415567027286a75ba1093ec4aca11f073e0f559c530cf3e0a757ad55c/librt-0.11.0-cp314-cp314t-win_amd64.whl", hash = "sha256:28edb433edde181112a908c78907af28f964eabc15f4dd16c9d66c834302677c", size = 124327, upload-time = "2026-05-10T18:17:05.465Z" }, + { url = "https://files.pythonhosted.org/packages/ce/62/b40b382fa0c66fee1478073eb8db352a4a6beda4a1adccf1df911d8c289c/librt-0.11.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dee008f20b542e3cd162ba338a7f9ec0f6d23d395f66fe8aeeec3c9d067ea253", size = 102572, upload-time = "2026-05-10T18:17:06.809Z" }, +] + +[[package]] +name = "llvmlite" +version = "0.47.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/88/a8952b6d5c21e74cbf158515b779666f692846502623e9e3c39d8e8ba25f/llvmlite-0.47.0.tar.gz", hash = "sha256:62031ce968ec74e95092184d4b0e857e444f8fdff0b8f9213707699570c33ccc", size = 193614, upload-time = "2026-03-31T18:29:53.497Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/0b/b9d1911cfefa61399821dfb37f486d83e0f42630a8d12f7194270c417002/llvmlite-0.47.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:74090f0dcfd6f24ebbef3f21f11e38111c4d7e6919b54c4416e1e357c3446b07", size = 37232770, upload-time = "2026-03-31T18:28:26.765Z" }, + { url = "https://files.pythonhosted.org/packages/46/27/5799b020e4cdfb25a7c951c06a96397c135efcdc21b78d853bbd9c814c7d/llvmlite-0.47.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ca14f02e29134e837982497959a8e2193d6035235de1cb41a9cb2bd6da4eedbb", size = 56275177, upload-time = "2026-03-31T18:28:31.01Z" }, + { url = "https://files.pythonhosted.org/packages/7e/51/48a53fedf01cb1f3f43ef200be17ebf83c8d9a04018d3783c1a226c342c2/llvmlite-0.47.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:12a69d4bb05f402f30477e21eeabe81911e7c251cecb192bed82cd83c9db10d8", size = 55128631, upload-time = "2026-03-31T18:28:36.046Z" }, + { url = "https://files.pythonhosted.org/packages/a2/50/59227d06bdc96e23322713c381af4e77420949d8cd8a042c79e0043096cc/llvmlite-0.47.0-cp311-cp311-win_amd64.whl", hash = "sha256:c37d6eb7aaabfa83ab9c2ff5b5cdb95a5e6830403937b2c588b7490724e05327", size = 38138400, upload-time = "2026-03-31T18:28:40.076Z" }, + { url = "https://files.pythonhosted.org/packages/fa/48/4b7fe0e34c169fa2f12532916133e0b219d2823b540733651b34fdac509a/llvmlite-0.47.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:306a265f408c259067257a732c8e159284334018b4083a9e35f67d19792b164f", size = 37232769, upload-time = "2026-03-31T18:28:43.735Z" }, + { url = "https://files.pythonhosted.org/packages/e6/4b/e3f2cd17822cf772a4a51a0a8080b0032e6d37b2dbe8cfb724eac4e31c52/llvmlite-0.47.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5853bf26160857c0c2573415ff4efe01c4c651e59e2c55c2a088740acfee51cd", size = 56275178, upload-time = "2026-03-31T18:28:48.342Z" }, + { url = "https://files.pythonhosted.org/packages/b6/55/a3b4a543185305a9bdf3d9759d53646ed96e55e7dfd43f53e7a421b8fbae/llvmlite-0.47.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:003bcf7fa579e14db59c1a1e113f93ab8a06b56a4be31c7f08264d1d4072d077", size = 55128632, upload-time = "2026-03-31T18:28:52.901Z" }, + { url = "https://files.pythonhosted.org/packages/2f/f5/d281ae0f79378a5a91f308ea9fdb9f9cc068fddd09629edc0725a5a8fde1/llvmlite-0.47.0-cp312-cp312-win_amd64.whl", hash = "sha256:f3079f25bdc24cd9d27c4b2b5e68f5f60c4fdb7e8ad5ee2b9b006007558f9df7", size = 38138692, upload-time = "2026-03-31T18:28:57.147Z" }, + { url = "https://files.pythonhosted.org/packages/77/6f/4615353e016799f80fa52ccb270a843c413b22361fadda2589b2922fb9b0/llvmlite-0.47.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:a3c6a735d4e1041808434f9d440faa3d78d9b4af2ee64d05a66f351883b6ceec", size = 37232771, upload-time = "2026-03-31T18:29:01.324Z" }, + { url = "https://files.pythonhosted.org/packages/31/b8/69f5565f1a280d032525878a86511eebed0645818492feeb169dfb20ae8e/llvmlite-0.47.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2699a74321189e812d476a43d6d7f652f51811e7b5aad9d9bba842a1c7927acb", size = 56275178, upload-time = "2026-03-31T18:29:05.748Z" }, + { url = "https://files.pythonhosted.org/packages/d6/da/b32cafcb926fb0ce2aa25553bf32cb8764af31438f40e2481df08884c947/llvmlite-0.47.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6c6951e2b29930227963e53ee152441f0e14be92e9d4231852102d986c761e40", size = 55128632, upload-time = "2026-03-31T18:29:11.235Z" }, + { url = "https://files.pythonhosted.org/packages/46/9f/4898b44e4042c60fafcb1162dfb7014f6f15b1ec19bf29cfea6bf26df90d/llvmlite-0.47.0-cp313-cp313-win_amd64.whl", hash = "sha256:c2e9adf8698d813a9a5efb2d4370caf344dbc1e145019851fee6a6f319ba760e", size = 38138695, upload-time = "2026-03-31T18:29:15.43Z" }, + { url = "https://files.pythonhosted.org/packages/1c/d4/33c8af00f0bf6f552d74f3a054f648af2c5bc6bece97972f3bfadce4f5ec/llvmlite-0.47.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:de966c626c35c9dff5ae7bf12db25637738d0df83fc370cf793bc94d43d92d14", size = 37232773, upload-time = "2026-03-31T18:29:19.453Z" }, + { url = "https://files.pythonhosted.org/packages/64/1d/a760e993e0c0ba6db38d46b9f48f6c7dceb8ac838824997fb9e25f97bc04/llvmlite-0.47.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ddbccff2aeaff8670368340a158abefc032fe9b3ccf7d9c496639263d00151aa", size = 56275176, upload-time = "2026-03-31T18:29:24.149Z" }, + { url = "https://files.pythonhosted.org/packages/84/3b/e679bc3b29127182a7f4aa2d2e9e5bea42adb93fb840484147d59c236299/llvmlite-0.47.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4a7b778a2e144fc64468fb9bf509ac1226c9813a00b4d7afea5d988c4e22fca", size = 55128631, upload-time = "2026-03-31T18:29:29.536Z" }, + { url = "https://files.pythonhosted.org/packages/be/f7/19e2a09c62809c9e63bbd14ce71fb92c6ff7b7b3045741bb00c781efc3c9/llvmlite-0.47.0-cp314-cp314-win_amd64.whl", hash = "sha256:694e3c2cdc472ed2bd8bd4555ca002eec4310961dd58ef791d508f57b5cc4c94", size = 39153826, upload-time = "2026-03-31T18:29:33.681Z" }, + { url = "https://files.pythonhosted.org/packages/40/a1/581a8c707b5e80efdbbe1dd94527404d33fe50bceb71f39d5a7e11bd57b7/llvmlite-0.47.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:92ec8a169a20b473c1c54d4695e371bde36489fc1efa3688e11e99beba0abf9c", size = 37232772, upload-time = "2026-03-31T18:29:37.952Z" }, + { url = "https://files.pythonhosted.org/packages/11/03/16090dd6f74ba2b8b922276047f15962fbeea0a75d5601607edb301ba945/llvmlite-0.47.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fa1cbd800edd3b20bc141521f7fd45a6185a5b84109aa6855134e81397ffe72b", size = 56275178, upload-time = "2026-03-31T18:29:42.58Z" }, + { url = "https://files.pythonhosted.org/packages/f5/cb/0abf1dd4c5286a95ffe0c1d8c67aec06b515894a0dd2ac97f5e27b82ab0b/llvmlite-0.47.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f6725179b89f03b17dabe236ff3422cb8291b4c1bf40af152826dfd34e350ae8", size = 55128632, upload-time = "2026-03-31T18:29:46.939Z" }, + { url = "https://files.pythonhosted.org/packages/4f/79/d3bbab197e86e0ff4f9c07122895b66a3e0d024247fcff7f12c473cb36d9/llvmlite-0.47.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6842cf6f707ec4be3d985a385ad03f72b2d724439e118fcbe99b2929964f0453", size = 39153839, upload-time = "2026-03-31T18:29:51.004Z" }, +] + +[[package]] +name = "matplotlib" +version = "3.10.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "contourpy" }, + { name = "cycler" }, + { name = "fonttools" }, + { name = "kiwisolver" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pillow" }, + { name = "pyparsing" }, + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/63/1b/4be5be87d43d327a0cf4de1a56e86f7f84c89312452406cf122efe2839e6/matplotlib-3.10.9.tar.gz", hash = "sha256:fd66508e8c6877d98e586654b608a0456db8d7e8a546eb1e2600efd957302358", size = 34811233, upload-time = "2026-04-24T00:14:13.539Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/8c/290f021104741fea63769c31494f5324c0cd249bf536a65a4350767b1f22/matplotlib-3.10.9-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:68cfdcede415f7c8f5577b03303dd94526cdb6d11036cecdc205e08733b2d2bb", size = 8306860, upload-time = "2026-04-24T00:12:01.207Z" }, + { url = "https://files.pythonhosted.org/packages/51/18/325cd32ece1120d1da51cc4e4294c6580190699490183fc2fe8cb6d61ec5/matplotlib-3.10.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfca0129678bd56379db26c52b5d77ed7de314c047492fbdc763aa7501710cfb", size = 8199254, upload-time = "2026-04-24T00:12:04.239Z" }, + { url = "https://files.pythonhosted.org/packages/79/db/e28c1b83e3680740aa78925f5fb2ae4d16207207419ad75ea9fe604f8676/matplotlib-3.10.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8e436d155fa8a3399dc62683f8f5d0e2e50d25d0144a73edd73f82eec8f4abfb", size = 8777092, upload-time = "2026-04-24T00:12:06.793Z" }, + { url = "https://files.pythonhosted.org/packages/55/fa/3ce7adfe9ba101748f465211660d9c6374c876b671bdb8c2bb6d347e8b94/matplotlib-3.10.9-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56fc0bd271b00025c6edfdc7c2dcd247372c8e1544971d62e1dc7c17367e8bf9", size = 9595691, upload-time = "2026-04-24T00:12:09.706Z" }, + { url = "https://files.pythonhosted.org/packages/36/c4/6960a76686ed668f2c60f84e9799ba4c0d56abdb36b1577b60c1d061d1ec/matplotlib-3.10.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a5a6104ed666402ba5106d7f36e0e0cdca4e8d7fa4d39708ca88019e2835a2eb", size = 9659771, upload-time = "2026-04-24T00:12:12.766Z" }, + { url = "https://files.pythonhosted.org/packages/7e/0d/271aace3342157c64700c9ff4c59c7b392f3dbab393692e8db6fbe7ab96c/matplotlib-3.10.9-cp311-cp311-win_amd64.whl", hash = "sha256:d730e984eddf56974c3e72b6129c7ca462ac38dc624338f4b0b23eb23ecba00f", size = 8205112, upload-time = "2026-04-24T00:12:15.773Z" }, + { url = "https://files.pythonhosted.org/packages/e2/ee/cb57ad4754f3e7b9174ce6ce66d9205fb827067e48a9f58ac09d7e7d6b77/matplotlib-3.10.9-cp311-cp311-win_arm64.whl", hash = "sha256:51bf0ddbdc598e060d46c16b5590708f81a1624cefbaaf62f6a81bf9285b8c80", size = 8132310, upload-time = "2026-04-24T00:12:18.645Z" }, + { url = "https://files.pythonhosted.org/packages/35/c6/5581e26c72233ebb2a2a6fed2d24fb7c66b4700120b813f51b0555acf0b6/matplotlib-3.10.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f0c3c28d9fbcc1fe7a03be236d73430cf6409c41fb2383a7ac52fe932b072cb1", size = 8319908, upload-time = "2026-04-24T00:12:21.323Z" }, + { url = "https://files.pythonhosted.org/packages/b7/18/4880dd762e40cd360c1bf06e890c5a97b997e91cb324602b1a19950ad5ce/matplotlib-3.10.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41cb28c2bd769aa3e98322c6ab09854cbcc52ab69d2759d681bba3e327b2b320", size = 8216016, upload-time = "2026-04-24T00:12:23.4Z" }, + { url = "https://files.pythonhosted.org/packages/32/91/d024616abdba99e83120e07a20658976f6a343646710760c4a51df126029/matplotlib-3.10.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ae20801130378b82d647ff5047c07316295b68dc054ca6b3c13519d0ea624285", size = 8789336, upload-time = "2026-04-24T00:12:26.096Z" }, + { url = "https://files.pythonhosted.org/packages/5c/04/030a2f61ef2158f5e4c259487a92ac877732499fb33d871585d89e03c42d/matplotlib-3.10.9-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6c63ebcd8b4b169eb2f5c200552ae6b8be8999a005b6b507ed76fb8d7d674fe2", size = 9604602, upload-time = "2026-04-24T00:12:29.052Z" }, + { url = "https://files.pythonhosted.org/packages/fc/c2/541e4d09d87bb6b5830fc28b4c887a9a8cf4e1c6cee698a8c05552ae2003/matplotlib-3.10.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d75d11c949914165976c621b2324f9ef162af7ebf4b057ddf95dd1dba7e5edcf", size = 9670966, upload-time = "2026-04-24T00:12:32.131Z" }, + { url = "https://files.pythonhosted.org/packages/04/a1/4571fc46e7702de8d0c2dc54ad1b2f8e29328dea3ee90831181f7353d93c/matplotlib-3.10.9-cp312-cp312-win_amd64.whl", hash = "sha256:d091f9d758b34aaaaa6331d13574bf01891d903b3dec59bfff458ef7551de5d6", size = 8217462, upload-time = "2026-04-24T00:12:35.226Z" }, + { url = "https://files.pythonhosted.org/packages/4b/d0/2269edb12aa30c13c8bcc9382892e39943ce1d28aab4ec296e0381798e81/matplotlib-3.10.9-cp312-cp312-win_arm64.whl", hash = "sha256:10cc5ce06d10231c36f40e875f3c7e8050362a4ee8f0ee5d29a6b3277d57bb42", size = 8136688, upload-time = "2026-04-24T00:12:37.442Z" }, + { url = "https://files.pythonhosted.org/packages/aa/d3/8d4f6afbecb49fc04e060a57c0fce39ea51cc163a6bd87303ccd698e4fa6/matplotlib-3.10.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b580440f1ff81a0e34122051a3dfabb7e4b7f9e380629929bde0eff9af72165f", size = 8320331, upload-time = "2026-04-24T00:12:39.688Z" }, + { url = "https://files.pythonhosted.org/packages/63/d9/9e14bc7564bf92d5ffa801ae5fac819ce74b925dfb55e3ebde61a3bbad3e/matplotlib-3.10.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b1b745c489cd1a77a0dc1120a05dc87af9798faebc913601feb8c73d89bf2d1e", size = 8216461, upload-time = "2026-04-24T00:12:42.494Z" }, + { url = "https://files.pythonhosted.org/packages/8a/17/4402d0d14ccf1dfc70932600b68097fbbf9c898a4871d2cbbe79c7801a32/matplotlib-3.10.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8f3bcac1ca5ed000a6f4337d47ba67dfddf37ed6a46c15fd7f014997f7bf865f", size = 8790091, upload-time = "2026-04-24T00:12:44.789Z" }, + { url = "https://files.pythonhosted.org/packages/3e/0b/322aeec06dd9b91411f92028b37d447342770a24392aa4813e317064dad5/matplotlib-3.10.9-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a8d66a55def891c33147ba3ba9bfcabf0b526a43764c818acbb4525e5ed0838", size = 9605027, upload-time = "2026-04-24T00:12:47.583Z" }, + { url = "https://files.pythonhosted.org/packages/74/88/5f13482f55e7b00bcfc09838b093c2456e1379978d2a146844aae05350ad/matplotlib-3.10.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d843374407c4017a6403b59c6c81606773d136f3259d5b6da3131bc814542cc2", size = 9671269, upload-time = "2026-04-24T00:12:50.878Z" }, + { url = "https://files.pythonhosted.org/packages/c5/e0/0840fd2f93da988ec660b8ad1984abe9f25d2aed22a5e394ff1c68c88307/matplotlib-3.10.9-cp313-cp313-win_amd64.whl", hash = "sha256:f4399f64b3e94cd500195490972ae1ee81170df1636fa15364d157d5bdd7b921", size = 8217588, upload-time = "2026-04-24T00:12:53.784Z" }, + { url = "https://files.pythonhosted.org/packages/47/b9/d706d06dd605c49b9f83a2aed8c13e3e5db70697d7a80b7e3d7915de6b17/matplotlib-3.10.9-cp313-cp313-win_arm64.whl", hash = "sha256:ba7b3b8ef09eab7df0e86e9ae086faa433efbfbdb46afcb3aa16aabf779469a8", size = 8136913, upload-time = "2026-04-24T00:12:56.501Z" }, + { url = "https://files.pythonhosted.org/packages/9b/45/6e32d96978264c8ca8c4b1010adb955a1a49cfaf314e212bbc8908f04a61/matplotlib-3.10.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:09218df8a93712bd6ea133e83a153c755448cf7868316c531cffcc43f69d1cc9", size = 8368019, upload-time = "2026-04-24T00:12:58.896Z" }, + { url = "https://files.pythonhosted.org/packages/86/0a/c8e3d3bba245f0f7fc424937f8ff7ef77291a36af3edb97ccd78aa93d84f/matplotlib-3.10.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:82368699727bfb7b0182e1aa13082e3c08e092fa1a25d3e1fd92405bff96f6d4", size = 8264645, upload-time = "2026-04-24T00:13:01.406Z" }, + { url = "https://files.pythonhosted.org/packages/3d/aa/5bf5a14fe4fed73a4209a155606f8096ff797aad89c6c35179026571133e/matplotlib-3.10.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3225f4e1edcb8c86c884ddf79ebe20ecd0a67d30188f279897554ccd8fded4dc", size = 8802194, upload-time = "2026-04-24T00:13:03.702Z" }, + { url = "https://files.pythonhosted.org/packages/dd/5e/b4be852d6bba6fd15893fadf91ff26ae49cb91aac789e95dde9d342e664f/matplotlib-3.10.9-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de2445a0c6690d21b7eb6ce071cebad6d40a2e9bdf10d039074a96ba19797b99", size = 9622684, upload-time = "2026-04-24T00:13:06.647Z" }, + { url = "https://files.pythonhosted.org/packages/4c/3d/ed428c971139112ef730f62770654d609467346d09d4b62617e1afd68a5a/matplotlib-3.10.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:b2b9516251cb89ff618d757daec0e2ed1bf21248013844a853d87ef85ab3081d", size = 9680790, upload-time = "2026-04-24T00:13:10.009Z" }, + { url = "https://files.pythonhosted.org/packages/e7/09/052e884aaf2b985c63cb79f715f1d5b6a3eaa7de78f6a52b9dbc077d5b53/matplotlib-3.10.9-cp313-cp313t-win_amd64.whl", hash = "sha256:e9fae004b941b23ff2edcf1567a857ed77bafc8086ffa258190462328434faf8", size = 8287571, upload-time = "2026-04-24T00:13:13.087Z" }, + { url = "https://files.pythonhosted.org/packages/f4/38/ae27288e788c35a4250491422f3db7750366fc8c97d6f36fbdecfc1f5518/matplotlib-3.10.9-cp313-cp313t-win_arm64.whl", hash = "sha256:6b63d9c7c769b88ab81e10dc86e4e0607cf56817b9f9e6cf24b2a5f1693b8e38", size = 8188292, upload-time = "2026-04-24T00:13:15.546Z" }, + { url = "https://files.pythonhosted.org/packages/d6/e6/3bd8afd04949f02eabc1c17115ea5255e19cacd4d06fc5abdde4eeb0052c/matplotlib-3.10.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:172db52c9e683f5d12eaf57f0f54834190e12581fe1cc2a19595a8f5acb4e77d", size = 8321276, upload-time = "2026-04-24T00:13:18.318Z" }, + { url = "https://files.pythonhosted.org/packages/41/86/86231232fff41c9f8e4a1a7d7a597d349a02527109c3af7d618366122139/matplotlib-3.10.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:97e35e8d39ccc85859095e01a53847432ba9a53ddf7986f7a54a11b73d0e143f", size = 8218218, upload-time = "2026-04-24T00:13:20.974Z" }, + { url = "https://files.pythonhosted.org/packages/85/8f/becc9722cafc64f5d2eb0b7c1bf5f585271c618a45dbd8fabeb021f898b6/matplotlib-3.10.9-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aba1615dabe83188e19d4f75a253c6a08423e04c1425e64039f800050a69de6b", size = 9608145, upload-time = "2026-04-24T00:13:23.228Z" }, + { url = "https://files.pythonhosted.org/packages/32/5d/f7e914f7d9325abff4057cee62c0fa70263683189f774473cbfb534cd13b/matplotlib-3.10.9-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34cf8167e023ad956c15f36302911d5406bd99a9862c1a8499ea6f7c0e015dc2", size = 9885085, upload-time = "2026-04-24T00:13:25.849Z" }, + { url = "https://files.pythonhosted.org/packages/a5/fd/fa69f2221534e80cc5772ac2b7d222011a2acafc2ec7216d5dd174c864ae/matplotlib-3.10.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:59476c6d29d612b8e9bb6ce8c5b631be6ba8f9e3a2421f22a02b192c7dd28716", size = 9672358, upload-time = "2026-04-24T00:13:28.906Z" }, + { url = "https://files.pythonhosted.org/packages/ab/1a/5a4f747a8b271cbb024946d2dd3c913ab5032ba430626f8c3528ada96b4b/matplotlib-3.10.9-cp314-cp314-win_amd64.whl", hash = "sha256:336b9acc64d309063126edcdaca00db9373af3c476bb94388fe9c5a53ad13e6f", size = 8349970, upload-time = "2026-04-24T00:13:31.904Z" }, + { url = "https://files.pythonhosted.org/packages/64/dc/95d60ecaefe30680a154b52ea96ab4b0dab547f1fd6aa12f5fb655e89cae/matplotlib-3.10.9-cp314-cp314-win_arm64.whl", hash = "sha256:2dc9477819ffd78ad12a20df1d9d6a6bd4fec6aaa9072681465fddca052f1456", size = 8272785, upload-time = "2026-04-24T00:13:34.511Z" }, + { url = "https://files.pythonhosted.org/packages/70/a0/005d68bc8b8418300ce6591f18586910a8526806e2ab663933d9f20a41e9/matplotlib-3.10.9-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:da4e09638420548f31c354032a6250e473c68e5a4e96899b4844cf39ddea23fe", size = 8367999, upload-time = "2026-04-24T00:13:36.962Z" }, + { url = "https://files.pythonhosted.org/packages/22/05/1236cc9290be70b2498af20ca348add76e3fffe7f67b477db5133a84f3ea/matplotlib-3.10.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:345f6f68ecc8da0ca56fad2ea08fde1a115eda530079eca185d50a7bc3e146c6", size = 8264543, upload-time = "2026-04-24T00:13:39.851Z" }, + { url = "https://files.pythonhosted.org/packages/cd/c2/071f5a5ff6c5bd63aaaf2f45c811d9bf2ced94bde188d9e1a519e21d0cba/matplotlib-3.10.9-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4edcfbd8565339aa62f1cd4012f7180926fdbe71850f7b0d3c379c175cd6b66c", size = 9622800, upload-time = "2026-04-24T00:13:42.296Z" }, + { url = "https://files.pythonhosted.org/packages/95/57/da7d1f10a85624b9e7db68e069dd94e58dc41dbf9463c5921632ecbe3661/matplotlib-3.10.9-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6be157fe17fc37cb95ac1d7374cf717ce9259616edec911a78d9d26dae8522d4", size = 9888561, upload-time = "2026-04-24T00:13:45.026Z" }, + { url = "https://files.pythonhosted.org/packages/67/b2/ef8d6bb59b0edb6c16c968b70f548aa13b54348972def5aa6ac85df67145/matplotlib-3.10.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:4e42042d54db34fda4e95a7bd3e5789c2a995d2dad3eb8850232ee534092fbbf", size = 9680884, upload-time = "2026-04-24T00:13:48.066Z" }, + { url = "https://files.pythonhosted.org/packages/61/1c/d21bfeb9931881ebe96bcfcff27c7ae4b160ae0ec291a714c42641a56d75/matplotlib-3.10.9-cp314-cp314t-win_amd64.whl", hash = "sha256:c27df8b3848f32a83d1767566595e43cfaa4460380974da06f4279a7ec143c39", size = 8432333, upload-time = "2026-04-24T00:13:51.008Z" }, + { url = "https://files.pythonhosted.org/packages/78/23/92493c3e6e1b635ccfff146f7b99e674808787915420373ac399283764c2/matplotlib-3.10.9-cp314-cp314t-win_arm64.whl", hash = "sha256:a49f1eadc84ca85fd72fa4e89e70e61bf86452df6f971af04b12c60761a0772c", size = 8324785, upload-time = "2026-04-24T00:13:53.633Z" }, + { url = "https://files.pythonhosted.org/packages/63/e2/9f66ca6a651a52abfe0d4964ce01439ed34f3f1e119de10ff3a07f403043/matplotlib-3.10.9-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:42fb814efabe95c06c1994d8ab5a8385f43a249e23badd3ba931d4308e5bca20", size = 8304420, upload-time = "2026-04-24T00:14:04.57Z" }, + { url = "https://files.pythonhosted.org/packages/e8/e8/467c03568218792906aa87b5e7bb379b605e056ed0c74fe00c051786d925/matplotlib-3.10.9-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f76e640a5268850bfda54b5131b1b1941cc685e42c5fa98ed9f2d64038308cba", size = 8197981, upload-time = "2026-04-24T00:14:07.233Z" }, + { url = "https://files.pythonhosted.org/packages/6f/87/afead29192170917537934c6aff4b008c805fff7b1ccea0c79120d96beda/matplotlib-3.10.9-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3fc0364dfbe1d07f6d15c5ebd0c5bf89e126916e5a8667dd4a7a6e84c36653d4", size = 8774002, upload-time = "2026-04-24T00:14:09.816Z" }, +] + +[[package]] +name = "matplotlib-inline" +version = "0.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bd/c0/9f7c9a46090390368a4d7bcb76bb87a4a36c421e4c0792cdb53486ffac7a/matplotlib_inline-0.2.2.tar.gz", hash = "sha256:72f3fe8fce36b70d4a5b612f899090cd0401deddc4ea90e1572b9f4bfb058c79", size = 8150, upload-time = "2026-05-08T17:33:33.49Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/09/5b161152e2d90f7b87f781c2e1267494aef9c32498df793f73ad0a0a494a/matplotlib_inline-0.2.2-py3-none-any.whl", hash = "sha256:3c821cf1c209f59fb2d2d64abbf5b23b67bcb2210d663f9918dd851c6da1fcf6", size = 9534, upload-time = "2026-05-08T17:33:32.055Z" }, +] + +[[package]] +name = "mypy" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ast-serialize" }, + { name = "librt", marker = "platform_python_implementation != 'PyPy'" }, + { name = "mypy-extensions" }, + { name = "pathspec" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/82/15/cca9d88503549ed6fedeaa1d448cdddd542ee8a490232d732e278036fbf2/mypy-2.1.0.tar.gz", hash = "sha256:81e76ad12c2d804512e9b13240d1588316531bfba07558286078bfbce9613633", size = 3898359, upload-time = "2026-05-11T18:37:36.237Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/a1/639f3024794a2a15899cb90707fe02e044c4412794c39c5769fd3df2e2ef/mypy-2.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a683016b16fe2f572dc04c72be7ee0504ac1605a265d0200f5cea695fb788f41", size = 14691685, upload-time = "2026-05-11T18:33:27.973Z" }, + { url = "https://files.pythonhosted.org/packages/3b/08/9a585dea4325f20d8b80dc78623fa50d1fd2173b710f6237afd6ba6ab39b/mypy-2.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1a293c534adb55271fef24a26da04b855540a8c13cc07bc5917b9fd2c394f2ca", size = 13555165, upload-time = "2026-05-11T18:32:16.107Z" }, + { url = "https://files.pythonhosted.org/packages/81/dc/7c42cc9c6cb01e8eb09961f1f738741d3e9c7e9d5c5b30ec69222625cd5f/mypy-2.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7406f4d048e71e576f5356d317e5b0a9e666dfd966bd99f9d14ca06e1a341538", size = 13994376, upload-time = "2026-05-11T18:32:39.256Z" }, + { url = "https://files.pythonhosted.org/packages/d4/fa/285946c33bce716e082c11dfeee9ee196eaf1f5042efb3581a31f9f205e4/mypy-2.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e0210d626fc8b31ccc90233754c7bc90e1f43205e85d96387f7db1285b55c398", size = 14864618, upload-time = "2026-05-11T18:34:49.765Z" }, + { url = "https://files.pythonhosted.org/packages/2b/83/82397f48af6c27e295d57979ded8490c9829040152cf7571b2f026aeb9a0/mypy-2.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3712c20deed54e814eaaa825603bada8ea1c390670a397c95b98405347acc563", size = 15102063, upload-time = "2026-05-11T18:34:05.855Z" }, + { url = "https://files.pythonhosted.org/packages/40/68/b02dec39057b88eb03dc0aa854732e26e8361f34f9d0e20c7614967d1eba/mypy-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fcaa0e479066e31f7cceb6a3bea39cb22b2ff51a6b2f24f193d19179ba17c389", size = 11060564, upload-time = "2026-05-11T18:35:36.494Z" }, + { url = "https://files.pythonhosted.org/packages/cf/a8/ea3dcbef31f99b634f2ee23bb0321cbc8c1b388b76a861eb849f13c347dc/mypy-2.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:0b1a5260c95aa443083f9ed3592662941951bca3d4ca224a5dc517c38b7cf666", size = 9966983, upload-time = "2026-05-11T18:37:14.139Z" }, + { url = "https://files.pythonhosted.org/packages/95/b1/55861beb5c339b44f9a2ba92df9e2cb1eeb4ae1eee674cdf7772c797778b/mypy-2.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:244358bf1c0da7722230bce60683d52e8e9fd030554926f15b747a84efb5b3af", size = 14874381, upload-time = "2026-05-11T18:37:31.784Z" }, + { url = "https://files.pythonhosted.org/packages/0b/b3/b7f770114b7d0ac92d0f76e8d93c2780844a70488a90e91821927850da86/mypy-2.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4ec7c57657493c7a75534df2751c8ae2cda383c16ecc55d2106c54476b1b16f6", size = 13665501, upload-time = "2026-05-11T18:34:23.063Z" }, + { url = "https://files.pythonhosted.org/packages/b6/f3/8ae2037967e2126689a0c11d99e2b707134a565191e92c60ca2572aec60a/mypy-2.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8161b6ff4392410023224f0969d17db93e1e154bc3e4ba62598e720723ae211", size = 14045750, upload-time = "2026-05-11T18:31:48.151Z" }, + { url = "https://files.pythonhosted.org/packages/a0/32/615eb5911859e43d054941b0d0a7d06cfa2870eba86529cf385b052b111c/mypy-2.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bf03e12003084a67395184d3eb8cbd6a489dc3655b5664b28c210a9e2403ab0b", size = 15061630, upload-time = "2026-05-11T18:37:06.898Z" }, + { url = "https://files.pythonhosted.org/packages/d4/03/4eafbfff8bfab1b87082741eae6e6a624028c984e6708b73bce2a8570c9d/mypy-2.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:20509760fd791c51579d573153407d226385ec1f8bcce55d730b354f3336bc22", size = 15288831, upload-time = "2026-05-11T18:31:18.07Z" }, + { url = "https://files.pythonhosted.org/packages/99/ee/919661478e5891a3c96e549c036e467e64563ab85995b10c53c8358e16a3/mypy-2.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:6753d0c1fdd6b1a23b9e4f283ce80b2153b724adcb2653b20b85a8a28ac6436b", size = 11135228, upload-time = "2026-05-11T18:34:31.23Z" }, + { url = "https://files.pythonhosted.org/packages/24/0a/6a12b9782ca0831a553192f351679f4548abc9d19a7cc93bb7feb02084c7/mypy-2.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:98ebb6589bb3b6d0c6f0c459d53ca55b8091fbc13d277c4041c885392e8195e8", size = 10040684, upload-time = "2026-05-11T18:36:48.199Z" }, + { url = "https://files.pythonhosted.org/packages/6e/dd/c7191469c777f07689c032a8f7326e393ea34c92d6d76eb7ce5ba57ea66d/mypy-2.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:35aac3bb114e03888f535d5eb51b8bafbb3266586b599da1940f9b1be3ec5bd5", size = 14852174, upload-time = "2026-05-11T18:31:38.929Z" }, + { url = "https://files.pythonhosted.org/packages/55/8c/aed55408879043d72bb9135f4d0d19a02b886dd569631e113e3d2706cb8d/mypy-2.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8de55a8c861f2a49331f807be98d90caeceeef520bde13d43a160207f8af613e", size = 13651542, upload-time = "2026-05-11T18:36:04.636Z" }, + { url = "https://files.pythonhosted.org/packages/3a/8e/f371a824b1f1fa8ea6e3dbb8703d232977d572be2329554a3bc4d960302f/mypy-2.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5fdf2941a07434af755837d9880f7d7d25f1dacb1af9dcd4b9b66f2220a3024e", size = 14033929, upload-time = "2026-05-11T18:35:55.742Z" }, + { url = "https://files.pythonhosted.org/packages/94/21/f54be870d6dd53a82c674407e0f8eed7174b05ec78d42e5abd7b42e84fd5/mypy-2.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e195b817c13f02352a9c124301f9f30f078405444679b6753c1b96b6eed37285", size = 15039200, upload-time = "2026-05-11T18:33:10.281Z" }, + { url = "https://files.pythonhosted.org/packages/17/99/bf21748626a40ce59fd29a39386ab46afec88b7bd2f0fa6c3a97c995523f/mypy-2.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5431d42af987ebd92ba2f71d45c85ed41d8e6ca9f5fd209a69f68f707d2469e5", size = 15272690, upload-time = "2026-05-11T18:32:07.205Z" }, + { url = "https://files.pythonhosted.org/packages/d6/d7/9e90d2cf47100bea550ed2bc7b0d4de3a62181d84d5e37da0003e8462637/mypy-2.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:767fe8c66dc3e01e19e1737d4c38ebefead16125e1b8e58ad421903b376f5c65", size = 11147435, upload-time = "2026-05-11T18:33:56.477Z" }, + { url = "https://files.pythonhosted.org/packages/ec/46/e5c449e858798e35ffc90946282a27c62a77be743fe17480e4977374eb91/mypy-2.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:ecfe70d43775ab99562ab128ce49854a362044c9f894961f68f898c23cb7429d", size = 10035052, upload-time = "2026-05-11T18:32:30.049Z" }, + { url = "https://files.pythonhosted.org/packages/b0/ca/b279a672e874aedd5498ae25f722dacc8aa86bbffb939b3f97cbb1cf6686/mypy-2.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:7354c5a7f69d9345c3d6e69921d57088eea3ddeeb6b20d34c1b3855b02c36ec2", size = 14848422, upload-time = "2026-05-11T18:35:45.984Z" }, + { url = "https://files.pythonhosted.org/packages/27/e6/3efe56c631d959b9b4454e208b0ac4b7f4f58b404c89f8bec7b49efdfc21/mypy-2.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:49890d4f76ac9e06ec117f9e09f3174da70a620a0c300953d8595c926e80947f", size = 13677374, upload-time = "2026-05-11T18:36:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/84/7f/8107ea87a44fd1f1b59882442f033c9c3488c127201b1d1d15f1cbd6022e/mypy-2.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:761be68e023ef5d94678772396a8af1220030f80837a3afd8d0aef3b419666f4", size = 14055743, upload-time = "2026-05-11T18:35:18.361Z" }, + { url = "https://files.pythonhosted.org/packages/51/4d/b6d34db183133b83761b9199a82d31557cdbb70a380d8c3b3438e11882a3/mypy-2.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c90345fc182dc363b891350457ec69c35140858538f38b4540845afcc32b1aef", size = 15020937, upload-time = "2026-05-11T18:34:59.618Z" }, + { url = "https://files.pythonhosted.org/packages/ff/d7/f08360c691d758acb02f45022c34d98b92892f4ea756644e1000d4b9f3d8/mypy-2.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b84802e7b5a6daf1f5e15bc9fcd7ddae77be13981ffab037f1c67bb84d67d135", size = 15253371, upload-time = "2026-05-11T18:36:41.081Z" }, + { url = "https://files.pythonhosted.org/packages/67/1b/09460a13719530a19bce27bd3bc8449e83569dd2ba7faf51c9c3c30c0b61/mypy-2.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:022c771234936ceac541ebaf836fe9e2abeb3f5e09aff21588fe543ff006fe21", size = 11326429, upload-time = "2026-05-11T18:34:13.526Z" }, + { url = "https://files.pythonhosted.org/packages/40/62/75dbf0f82f7b6680340efc614af29dd0b3c17b8a4f1cd09b8bd2fd6bc814/mypy-2.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:498207db725cec88829a6a5c2fc771205fd043719ef98bc49aba8fb9fc4e6d57", size = 10218799, upload-time = "2026-05-11T18:32:23.491Z" }, + { url = "https://files.pythonhosted.org/packages/b2/66/caca04ed7d972fb6eb6dd1ccd6df1de5c38fae8c5b3dc1c4e8e0d85ee6b9/mypy-2.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:7d5e5cad0efeba72b93cd17490cc0d69c5ac9ca132994fe3fb0314808aeeb83e", size = 15923458, upload-time = "2026-05-11T18:35:28.64Z" }, + { url = "https://files.pythonhosted.org/packages/ed/52/2d90cbe49d014b13ed7ff337930c30bad35893fe38a1e4641e756bb62191/mypy-2.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ff715050c127d724fd260a2e666e7747fdd83511c0c47d449d98238970aef780", size = 14757697, upload-time = "2026-05-11T18:36:14.208Z" }, + { url = "https://files.pythonhosted.org/packages/ac/37/d98f4a14e081b238992d0ed96b6d39c7cc0148c9699eb71eaa68629665ea/mypy-2.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:82208da9e09414d520e912d3e462d454854bed0810b71540bb016dcbca7308fd", size = 15405638, upload-time = "2026-05-11T18:33:48.249Z" }, + { url = "https://files.pythonhosted.org/packages/a3/c2/15c46613b24a84fad2aea1248bf9619b99c2767ae9071fe224c179a0b7d4/mypy-2.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e79ebc1b904b84f0310dff7469655a9c36c7a68bddb37bdd42b67a332df61d08", size = 16215852, upload-time = "2026-05-11T18:32:50.296Z" }, + { url = "https://files.pythonhosted.org/packages/5c/90/9c16a57f482c76d25f6379762b56bbf65c711d8158cf271fb2802cfb0640/mypy-2.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e583edc957cfb0deb142079162ae826f58449b116c1d442f2d91c69d9fced081", size = 16452695, upload-time = "2026-05-11T18:33:38.182Z" }, + { url = "https://files.pythonhosted.org/packages/0f/4c/215a4eeb63cacc5f17f516691ea7285d11e249802b942476bff15922a314/mypy-2.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b33b6cd332695bba180d55e717a79d3038e479a2c49cc5eb3d53603409b9a5d7", size = 12866622, upload-time = "2026-05-11T18:34:39.945Z" }, + { url = "https://files.pythonhosted.org/packages/4b/50/1043e1db5f455ffe4c9ab22747cd8ca2bc492b1e4f4e21b130a44ee2b217/mypy-2.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:4f910fe825376a7b66ef7ca8c98e5a149e8cd64c19ae71d84047a74ee060d4e6", size = 10610798, upload-time = "2026-05-11T18:36:31.444Z" }, + { url = "https://files.pythonhosted.org/packages/0d/2a/13ca1f292f6db1b98ff495ef3467736b331621c5917cad984b7043e7348d/mypy-2.1.0-py3-none-any.whl", hash = "sha256:a663814603a5c563fb87a4f96fb473eeb30d1f5a4885afcf44f9db000a366289", size = 2693302, upload-time = "2026-05-11T18:31:29.246Z" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, +] + +[[package]] +name = "narwhals" +version = "2.21.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/a0/6198c56d42ef2f3c6ed0c42ba30dbcefdc86a91262d7d449010770ae085b/narwhals-2.21.2.tar.gz", hash = "sha256:5c5b2d0b47aef7c73ea412cfcbcd467f2f2d5be73e3c2ab19d78f4a97718790a", size = 632176, upload-time = "2026-05-16T08:49:08.314Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/77/928ea2e70641ca177a11140062cc5840d421795f2e82749d408d0cce900a/narwhals-2.21.2-py3-none-any.whl", hash = "sha256:7bb57c3700486039215455b9bf2d64261915cc0fd845cc30272d631df696b251", size = 451201, upload-time = "2026-05-16T08:49:05.536Z" }, +] + +[[package]] +name = "numba" +version = "0.65.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "llvmlite" }, + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f6/c5/db2ac3685833d626c0dcae6bd2330cd68433e1fd248d15f70998160d3ad7/numba-0.65.1.tar.gz", hash = "sha256:19357146c32fe9ed25059ab915e8465fb13951cf6b0aace3826b76886373ab23", size = 2765600, upload-time = "2026-04-24T02:02:56.551Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/96/b3/650500c2eab4534d98e9166f4298e0f3c69c742afdf24e6eabccd1f16ad8/numba-0.65.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:7020d74b19cdb8cff16506542fdd510756e28c5e7f3bd0b7f574f0f42272fcd9", size = 2680563, upload-time = "2026-04-24T02:02:18.414Z" }, + { url = "https://files.pythonhosted.org/packages/44/0b/0615dbedb98f5b32a35a53290fbdc6e22306968109278d7e58df82d7a9f6/numba-0.65.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f80ed83774b5173abd6581cd8d2165d1d38e13d2e5c8155c0c0b421784745420", size = 3745018, upload-time = "2026-04-24T02:02:20.252Z" }, + { url = "https://files.pythonhosted.org/packages/49/aa/4361698f35bf63bff67dfe6c90493731177f48ede954f77b0588731537bc/numba-0.65.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7ed425a43b0a5f9772f2f4e2dd0bbd12eabecae1af0b24efcfd4e053f012aac6", size = 3450962, upload-time = "2026-04-24T02:02:22.449Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9a/af61ec03b3116c161fd7a06b9e8a265729a8718458333e8ffbb06d9a3978/numba-0.65.1-cp311-cp311-win_amd64.whl", hash = "sha256:df40a5028a975b9ea66f6a2a3f7abbdbd541a863070e34ed367aff21141248e4", size = 2747417, upload-time = "2026-04-24T02:02:24.43Z" }, + { url = "https://files.pythonhosted.org/packages/57/bc/76f8f8c5cf9adee47fdb7bbb03be8900f76f902d451d7477cf12b845e1de/numba-0.65.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:ac3f1e77c352dd0ea9712732c2d8f9ca507717435eec5b5013bf138ac33c4a08", size = 2681371, upload-time = "2026-04-24T02:02:26.105Z" }, + { url = "https://files.pythonhosted.org/packages/69/47/a415af0283e4db0398104c6d1c11c9861a98dc67a7aa442a7769ed5d6196/numba-0.65.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:52bc6f3ceb8fcaff9b2ae26b4c6b1e9fee39db8d355534c0fe4f39a901246b84", size = 3802467, upload-time = "2026-04-24T02:02:27.712Z" }, + { url = "https://files.pythonhosted.org/packages/46/36/246f73ec99cfeab2f2cb2ce7d4218766cc36a2da418901223f4f4da9c813/numba-0.65.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90ca10b3463bae0bd70589726fe3c77d01d6b5fc86bee54bcdf9fb6b47c28977", size = 3502628, upload-time = "2026-04-24T02:02:29.763Z" }, + { url = "https://files.pythonhosted.org/packages/db/9e/3c679b2ee078425b9e99a91e44f8d132a6830d8ccce5227bc5e9181aeed8/numba-0.65.1-cp312-cp312-win_amd64.whl", hash = "sha256:5971c632be2a2351500431f46213821dba8d02b18a9f7d02fd36bd2743e41a6a", size = 2750611, upload-time = "2026-04-24T02:02:31.477Z" }, + { url = "https://files.pythonhosted.org/packages/79/37/14a4579049c1eb673afd0de0cb4842982acd55b9ce2643e763db858bcea0/numba-0.65.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:1735c15c1134a5108b4d6a5c77fc0947924ea066a738dc09a52008c13df9cad3", size = 2681344, upload-time = "2026-04-24T02:02:33.65Z" }, + { url = "https://files.pythonhosted.org/packages/a0/22/b8d873f6466b20aa563fc9b33acd48dec89a07803ddaa2f1c8ca1cd33126/numba-0.65.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c09f49117ef255e1f1c6dad0c7a1ed39868243862a73be5706793241a3755f1b", size = 3810619, upload-time = "2026-04-24T02:02:36.041Z" }, + { url = "https://files.pythonhosted.org/packages/62/08/e16a8b5d9a018962ebb5c66be662317cde32b9f5dab08441f90bed5522fb/numba-0.65.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:594a8680b3fadac99e97e489b1fd89007177e5336713745c3b769528c635a464", size = 3509783, upload-time = "2026-04-24T02:02:38.245Z" }, + { url = "https://files.pythonhosted.org/packages/fd/a5/03c970d57f4c1741354837353ce39fb5206952ae1dba8922d29c86f64805/numba-0.65.1-cp313-cp313-win_amd64.whl", hash = "sha256:85be74c0d036842699a30058f82fb88fc5ffdc59f7615cab5792ea92914c9b62", size = 2750534, upload-time = "2026-04-24T02:02:39.903Z" }, + { url = "https://files.pythonhosted.org/packages/4f/2e/8aed9b726d9ba5f11ad287645fd479e88278db3060a25cb1225d730eb2b7/numba-0.65.1-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:33f5eb68eb1c843511615d14663ce60258525d6a4c65ab040e2c2b0c4cf17450", size = 2681554, upload-time = "2026-04-24T02:02:41.812Z" }, + { url = "https://files.pythonhosted.org/packages/87/96/f3eb235fafa82a34e2ab5dd7dc9ffff998ebf5f0bbc23fa56a96aeb44da6/numba-0.65.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:71e73029bf53a62cc6afcf96be4bd942290d8b4c55f0a454fb536158115790f7", size = 3779602, upload-time = "2026-04-24T02:02:43.726Z" }, + { url = "https://files.pythonhosted.org/packages/09/90/b0f09b48752d23640b8284f22aa597737e8adaddc7fbfacc4708b7f73a4c/numba-0.65.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a07635e0be926b9bdbffb09137c230fb13f6ec0e564914ba937cee12ce3eb35", size = 3479532, upload-time = "2026-04-24T02:02:45.427Z" }, + { url = "https://files.pythonhosted.org/packages/56/46/3f7fc04fb853559e74b210e0b62c19974ec844cefec611f9e535f4da3761/numba-0.65.1-cp314-cp314-win_amd64.whl", hash = "sha256:2a20fcdabdefbdacf88d85caf70c3b18c4bcb7ebb8f82e6a19486383dd26ab63", size = 2752637, upload-time = "2026-04-24T02:02:47.664Z" }, + { url = "https://files.pythonhosted.org/packages/81/7b/c1a341a9067367778f4152a5f01061cf281fb09582c92c510ec4918cabf6/numba-0.65.1-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:548dd4b3a4508d5062768d1514b2cd7b015f9a25ec7af651c50dee243965e652", size = 2684600, upload-time = "2026-04-24T02:02:49.653Z" }, + { url = "https://files.pythonhosted.org/packages/03/36/98ddbcf3e4f04a6dd07e1c67249955920579ba4af6bb6868e3088f4ed282/numba-0.65.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:78abc28feff2c2ff8307fff3975b6438352759c9acb797ecd6b1fb6e7e39e31d", size = 3817198, upload-time = "2026-04-24T02:02:51.266Z" }, + { url = "https://files.pythonhosted.org/packages/a3/83/0dad21057ece5a835599f5d24099b091703995e23dbbf894f259e91c010b/numba-0.65.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee7676cb389555805f9b9a1840cbcd1ea6c8bd5376ab6918e3a29c5ea1dbda20", size = 3533862, upload-time = "2026-04-24T02:02:52.987Z" }, + { url = "https://files.pythonhosted.org/packages/32/36/8be7118ffd4c8440881046eac3d0982cc5ab42909508cf5d67024d62a2e4/numba-0.65.1-cp314-cp314t-win_amd64.whl", hash = "sha256:20609346e3bd75204950dcbbfe383a8d7dbf4902f442aedbf00f97fef4aa8f38", size = 2758237, upload-time = "2026-04-24T02:02:54.612Z" }, +] + +[[package]] +name = "numpy" +version = "2.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/ad/fed0499ce6a338d2a03ebae59cd15093910c8875328855781952abf6c2fe/numpy-2.4.6.tar.gz", hash = "sha256:f3a3570c4a2a16746ac2c31a7c7c7b0c186b95ce902e33db6f28094ed7387dda", size = 20735807, upload-time = "2026-05-18T23:37:14.07Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/49/ec46835a70be8fa6446c495126ac84fdb28cb2558e1620ffb87a10c8b64c/numpy-2.4.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0280e0356c0829a18d9de1cb7eee50ec22ca639878d7240307ca0943d73cd2c4", size = 16969194, upload-time = "2026-05-18T23:33:13.503Z" }, + { url = "https://files.pythonhosted.org/packages/0e/0d/f5957185c0ee2f3e12f78715aa9e3b353fd83633316c8532b38faa37e3f6/numpy-2.4.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:110f8b71aacb688ec69062bb7f6938a0f8acb01b7c1c4beb453c65b6d234584d", size = 14964111, upload-time = "2026-05-18T23:33:17.795Z" }, + { url = "https://files.pythonhosted.org/packages/ad/40/40a40ee0ddf7ceb782c49af278894b686e586d65d8c1889c8b5da01a3d7d/numpy-2.4.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:4cfe66903cc32a9921a6733d96b19bb6abf310397581bbad89c228f5abaf0ee8", size = 5469159, upload-time = "2026-05-18T23:33:20.654Z" }, + { url = "https://files.pythonhosted.org/packages/63/13/f9a8046535cb21deae82f8d03de9617e08882d274fad2539630761888228/numpy-2.4.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8155154c7c691289fe18f510b5d4657c68c67989f293f0535a91360392ff6538", size = 6798936, upload-time = "2026-05-18T23:33:22.987Z" }, + { url = "https://files.pythonhosted.org/packages/33/a8/6fa8c1a345a8c85dbb21932c447bee07c30a2c2a3f31e369c0a84b300147/numpy-2.4.6-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ab0a9c4ffb1a6d95ef519fe4247dba8eb6b18ad93999f76b7f657039acabd47", size = 15966692, upload-time = "2026-05-18T23:33:26.62Z" }, + { url = "https://files.pythonhosted.org/packages/02/03/74fe2a4cb3817d94d86402f2506554130a2f01414e299b5a843e5a8a957f/numpy-2.4.6-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:89cd468399cfd2504718f0ba50e410dca55a170b61a02ad92bb18c8a65186e93", size = 16918164, upload-time = "2026-05-18T23:33:29.955Z" }, + { url = "https://files.pythonhosted.org/packages/c5/80/3615be3313f7e7696609bc194b9f0101da809df79e859bdb84e0cd043f46/numpy-2.4.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2d37ab77531417474168eb79d6d80b14f821a966818505d03013d0833edb7a8", size = 17322877, upload-time = "2026-05-18T23:33:34.724Z" }, + { url = "https://files.pythonhosted.org/packages/ca/ac/a691e0fe2675e370d0e08ff905adc49a1c8830e8cae03efe4477e92cd55d/numpy-2.4.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f407cb6b8e9d6d8c626bc73c945db1706035af8fd632295547bf1c9e46d092d6", size = 18651487, upload-time = "2026-05-18T23:33:38.217Z" }, + { url = "https://files.pythonhosted.org/packages/15/a7/9bc1cd626d7bf6869bfedf27b91b6ab5dd607758bf8e959d6fa80c6a59cb/numpy-2.4.6-cp311-cp311-win32.whl", hash = "sha256:ddea102b48f9e339f3948bf22040944184627a30fdf7f858667673b9c5f033c8", size = 6233945, upload-time = "2026-05-18T23:33:41.331Z" }, + { url = "https://files.pythonhosted.org/packages/c5/31/7fc6239c12bce7e931463251cca4426c465e1876ba3cc785402ef4dd8f4e/numpy-2.4.6-cp311-cp311-win_amd64.whl", hash = "sha256:1e254a00cdf42b1e4d5b3d68d33af63268d41340d8885df2ab6470f2e1500147", size = 12608406, upload-time = "2026-05-18T23:33:44.131Z" }, + { url = "https://files.pythonhosted.org/packages/27/83/140f85a466595a16382996a1bf06b2b54bcd597488921b0c9daaeeda72af/numpy-2.4.6-cp311-cp311-win_arm64.whl", hash = "sha256:ed9749eef4cbd126da3dc1d6bcb3a57f5eb7ac6a6484146bdbf743f552dfc577", size = 10479528, upload-time = "2026-05-18T23:33:50.725Z" }, + { url = "https://files.pythonhosted.org/packages/95/2a/3d7b5ac8aac24feaf9ad7ed58f45b0bbc06d37e4338ae84c9f2298b570f9/numpy-2.4.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:001fbb8e08d942dd57599e781f2472269ee7f2755fae407b4f67b2f0b17da3f1", size = 16689119, upload-time = "2026-05-18T23:33:54.065Z" }, + { url = "https://files.pythonhosted.org/packages/ea/12/92c4c131527599e8288d6918e888d88726f84d805d784b771f32408aeaef/numpy-2.4.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ebfb099f8dcf083deef3ac1ca4c1503f387cf76296fcb3816b66f5ecb5f54fdb", size = 14699246, upload-time = "2026-05-18T23:33:57.621Z" }, + { url = "https://files.pythonhosted.org/packages/ad/fe/c0a6b7b2ca128a8fb228575147073b660656734b8ebe4d76c8fd748dcc79/numpy-2.4.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:3213d622a0283a39a93d188f3cf72b26862df52fbb4ca3697f51705016523d41", size = 5204410, upload-time = "2026-05-18T23:34:00.302Z" }, + { url = "https://files.pythonhosted.org/packages/f3/d4/9770d14ba719432bb90a421bfd443872ed0f70f7264b64bec12ea363d5fd/numpy-2.4.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:357cc07a6d7b0b182ff02249616a03742827ebb1277546b5c7cd7f7620a45698", size = 6551240, upload-time = "2026-05-18T23:34:02.852Z" }, + { url = "https://files.pythonhosted.org/packages/c9/c6/50a46a6205feba2343f1d6d17438107c5dc491ed1c736e6ea68689fd906b/numpy-2.4.6-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f9fb9157b4ce2971008323afe46053787b526ef624fea915b261468a8421a0f", size = 15671012, upload-time = "2026-05-18T23:34:05.485Z" }, + { url = "https://files.pythonhosted.org/packages/99/60/14115e6364fa676c5397c2ad3004e527e9aa487abf5d0706ec81bbd08529/numpy-2.4.6-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90f9849678c75fe7afa2d348ac842c168b0a4d3d61919687216dfc547976d853", size = 16645538, upload-time = "2026-05-18T23:34:09.265Z" }, + { url = "https://files.pythonhosted.org/packages/ae/c5/693cbe59e57db94d2231fa519ca3978dc9e19da5a8f088588f5c6e947ff2/numpy-2.4.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c1a2af6c6ef86344a6b0db6b97834208bf598db514f2b155042439b62605601a", size = 17020706, upload-time = "2026-05-18T23:34:13.053Z" }, + { url = "https://files.pythonhosted.org/packages/ef/fc/85b7c4eff9b4966ade25c2273cf7e7012e92366c032058653934b37de044/numpy-2.4.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e5805d5a22fd19c8ccff10a9561f9df94436b0545619ea579db2d3c35294bce2", size = 18368541, upload-time = "2026-05-18T23:34:17.024Z" }, + { url = "https://files.pythonhosted.org/packages/f6/81/e1b27545deedce7f4a0b348618c6b62d74e36a4dc9ccd42f3eb2f85eee32/numpy-2.4.6-cp312-cp312-win32.whl", hash = "sha256:e3eeb0aabd6bd5ce64faae67e9935203a6991b4bc2a485a767fbafb2c5125f45", size = 5962825, upload-time = "2026-05-18T23:34:20.3Z" }, + { url = "https://files.pythonhosted.org/packages/ab/ca/feab00bd44aa5fe1ad2c18f08b4d3bb92e26484b0b1d1443897809ed528c/numpy-2.4.6-cp312-cp312-win_amd64.whl", hash = "sha256:d8e8286dd7cea7895157318d1b91cdacac64c479f3cbc8dce548331728484751", size = 12321687, upload-time = "2026-05-18T23:34:23.095Z" }, + { url = "https://files.pythonhosted.org/packages/63/cf/5a6d34850a39d1093558564f77ee8e8e0bee5061151b8f05a55711001ec7/numpy-2.4.6-cp312-cp312-win_arm64.whl", hash = "sha256:4081eb135ac24158bd51cdfbef16f1c64df7063b1143f24731387137c092bec8", size = 10221482, upload-time = "2026-05-18T23:34:25.876Z" }, + { url = "https://files.pythonhosted.org/packages/fb/82/bdab26d7438c6791ca31b7c024ca37c1eab8b726ba236129005cd4a06e45/numpy-2.4.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:511dbaf848decaaaf4b4ca48032619fb3138710c4bf7da7617765edad1ef96b0", size = 16684648, upload-time = "2026-05-18T23:34:29.41Z" }, + { url = "https://files.pythonhosted.org/packages/1b/30/a80189bcc7f5e4258b3fbc3968d909d1756f54d023299ecc39ad6fdb9ef8/numpy-2.4.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bf162abab1c1a736333192707cef898e735a5ca00f38f27eeedf44b39d9e85eb", size = 14693902, upload-time = "2026-05-18T23:34:33.013Z" }, + { url = "https://files.pythonhosted.org/packages/97/12/70b5d0d7c15e1ebb8a6a84a8caa1d19e181d84fb58bb6d70aca29099dec1/numpy-2.4.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:043191bfa8eab18c776647b62723ac9dddece59743b13f49b2016094129c2b3f", size = 5198992, upload-time = "2026-05-18T23:34:36.132Z" }, + { url = "https://files.pythonhosted.org/packages/ba/8c/ebd2a8f8a83541f8d38cc5667e8c2b69cecfd30da6e45693e8158857d44b/numpy-2.4.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:6180d8b35af935aed8ece3a85e0a43f87393ae0ac87c8d2c8bd2c993f7270ef3", size = 6546944, upload-time = "2026-05-18T23:34:38.484Z" }, + { url = "https://files.pythonhosted.org/packages/bb/c5/7b863a97a91671a0338f4253bd3b5a3d3852f0692dae91711c9f4a10e787/numpy-2.4.6-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72fbe16c6fac95aedf5937fa873445cec2110be35d8a4e9433d7501fd98dae6b", size = 15669392, upload-time = "2026-05-18T23:34:41.257Z" }, + { url = "https://files.pythonhosted.org/packages/a5/9d/3584b9984ca4c047aea75214ce1a4c4c73d849bd71b604264b7f5653f8a8/numpy-2.4.6-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a7830bab239b79cda9c08c2da014761cafb48da6150e1da17ac06283f43b6089", size = 16633220, upload-time = "2026-05-18T23:34:45.075Z" }, + { url = "https://files.pythonhosted.org/packages/05/ae/7c67fba23bd98caec7c99261f3a16072ade14813486b0282cb29846de832/numpy-2.4.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ef4aea96ce4d3b074422cb4f2f64e216bf9e213004bb58ecfdf50ea02ea8eb9a", size = 17020800, upload-time = "2026-05-18T23:34:49.065Z" }, + { url = "https://files.pythonhosted.org/packages/d9/5d/3b6725cb31d983c5e66916f5d36f6d7e5521129e4c4404d64f918292a5b6/numpy-2.4.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dfa20cc6ca228e6b155b11da03825975ce66aea520985dbbddf0f2a5a495c605", size = 18357600, upload-time = "2026-05-18T23:34:52.709Z" }, + { url = "https://files.pythonhosted.org/packages/f7/da/2ccc6c2fe8898dee01d90c75c5f5f914a23daf99e3e0f59516a08760c8b5/numpy-2.4.6-cp313-cp313-win32.whl", hash = "sha256:56b39e5e0622a09a25bf5baf62f4bcf0cb8a41ae6e2819cf49bbc5a74c083f91", size = 5961134, upload-time = "2026-05-18T23:34:55.618Z" }, + { url = "https://files.pythonhosted.org/packages/b5/cd/9cc4dc876fb065d5c220aae4d5e14826b2715331bb7618ce1fb07a679d99/numpy-2.4.6-cp313-cp313-win_amd64.whl", hash = "sha256:c4fc99836233ea196540b17ab0983aff60ed07941751930f5f4d05bc3b3b7359", size = 12318598, upload-time = "2026-05-18T23:34:58.928Z" }, + { url = "https://files.pythonhosted.org/packages/39/1e/c0bcba1f8694116485fe28fd1be698c278fcda4141c5b0e53a2aed8b12a8/numpy-2.4.6-cp313-cp313-win_arm64.whl", hash = "sha256:a7c711e21628b52034bb5ab8d1bce291f752fcc5e92accc615778acee1ff4778", size = 10222272, upload-time = "2026-05-18T23:35:02.167Z" }, + { url = "https://files.pythonhosted.org/packages/63/6d/cc5619247c8f4204e507f5883528372e4ac4bb189e579fb859a12e480b1f/numpy-2.4.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:112b06a867b235ef466ed3508ddf0238050df9c727cafb5301ac385b899189a1", size = 14821197, upload-time = "2026-05-18T23:35:05.468Z" }, + { url = "https://files.pythonhosted.org/packages/00/58/f1c39161c87d9e9bed660f1ed4bafc0e403d5ec9650b6dd77aead07d489b/numpy-2.4.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:eaf7fa2de5c0be8ae6ff8e9bea2ccd725e980541244521d8d4b5f3354a27babe", size = 5326287, upload-time = "2026-05-18T23:35:08.693Z" }, + { url = "https://files.pythonhosted.org/packages/af/57/3917ab0fd97f271a8694513581b8a36c655f111c446852c302f04ccdb6fc/numpy-2.4.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:7265a2f3d436e54ef9f2b52b5c937e6be778781bd97a590319d7348f1c1ca997", size = 6646763, upload-time = "2026-05-18T23:35:11.459Z" }, + { url = "https://files.pythonhosted.org/packages/eb/0f/037e64c494b67581ae18193d770adef354c41f3f2c8ebf865602d949bf8f/numpy-2.4.6-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f74a575920ab21fe304421a3fc28793d82e299cae9eccb37084e9fc7f3617c20", size = 15728070, upload-time = "2026-05-18T23:35:14.79Z" }, + { url = "https://files.pythonhosted.org/packages/21/a6/5d2bae9c9542eb4df16dc9c46dc79c186e9bad53805dfa5399a6023c6db0/numpy-2.4.6-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ede83e07a75dd06bc501566c1eca2afc0d61677c1472ac9ad93fdee6e638a48d", size = 16681752, upload-time = "2026-05-18T23:35:18.836Z" }, + { url = "https://files.pythonhosted.org/packages/92/14/23d1dfb410ae362cd59ce53e936b1513d545eb40db3949ced632e19a459e/numpy-2.4.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:68bb27509ac1b9a3443094260f6326150663b06abe40b73a2f81160623da5b67", size = 17086024, upload-time = "2026-05-18T23:35:22.52Z" }, + { url = "https://files.pythonhosted.org/packages/4b/6e/23595a2c642cdf3bc567877064bdd7f91c8b0038a4453cf2daf7248eafe9/numpy-2.4.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a0df0043bdb289bde1f62da130d20df23d58b45429f752bc7a8fc5325a225ecd", size = 18403398, upload-time = "2026-05-18T23:35:26.398Z" }, + { url = "https://files.pythonhosted.org/packages/8a/90/0ac3bc947217e66dec77e7cbc6a1979d1af70b6461b82f620d3bccd5e4c8/numpy-2.4.6-cp313-cp313t-win32.whl", hash = "sha256:29a287e0cf63ff528da061de6b9f64a4618da591ca1046aafc54062e40ca7eab", size = 6084971, upload-time = "2026-05-18T23:35:29.387Z" }, + { url = "https://files.pythonhosted.org/packages/77/71/5673e351671a1d2bd6063b91b44f70c0affea7d1516fa7a6572941ba4aa1/numpy-2.4.6-cp313-cp313t-win_amd64.whl", hash = "sha256:25c692919ac5a01f170a3bfcd62d745b24fd095c353d50812637d6fcab442e75", size = 12458532, upload-time = "2026-05-18T23:35:32.175Z" }, + { url = "https://files.pythonhosted.org/packages/3f/88/19d3503c5046e688f049274b27a3ef3d771152fa80d3ba3d01a3dff61abe/numpy-2.4.6-cp313-cp313t-win_arm64.whl", hash = "sha256:1e978ec1e8bd0e0e4de6bb75de9d30cbb74db6b6a2bb727618613703ca0167dd", size = 10291881, upload-time = "2026-05-18T23:35:35.465Z" }, + { url = "https://files.pythonhosted.org/packages/f8/91/3ab2044d05fd16d343c5ac2e69b127f1b2854040dd20b193257c78028bd3/numpy-2.4.6-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06ca2f61ec4385a07a6977c55ba998a4466c123642b4a32694d3128fce18c079", size = 16683458, upload-time = "2026-05-18T23:35:38.353Z" }, + { url = "https://files.pythonhosted.org/packages/8e/62/764ce66fa4147ae6d73071a3abf804ffe606f174618697c571acdf26a7c9/numpy-2.4.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:38efbc8de75c7a0fc1ac190162d892787f3f47b57cc291231aafee36b80982b7", size = 14704559, upload-time = "2026-05-18T23:35:42.14Z" }, + { url = "https://files.pythonhosted.org/packages/60/61/23f27c172f022e04025b7dc2367f4d63c1a398120607ec896228649a6f48/numpy-2.4.6-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:d581b735e177fdcdce6fed8e7e8880a3fb6ee4e3653a3ac6af01c6f4c03effc5", size = 5209716, upload-time = "2026-05-18T23:35:45.377Z" }, + { url = "https://files.pythonhosted.org/packages/03/71/21cf70dc6ea3e3acb95fc53a265b2fc248b981f0194ceb5b475271b8809d/numpy-2.4.6-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:0a041d3d761dc3c35cc56ce0351506a02bcbc25f7b169f652435141a17db9096", size = 6543947, upload-time = "2026-05-18T23:35:47.926Z" }, + { url = "https://files.pythonhosted.org/packages/d5/91/64288395ee1799bd2e0b04a305dce9666da90c961e1f3fe982a05ee1c036/numpy-2.4.6-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:40fdc1ae7125e518ea98e53e69a4ebc27e1fd50510c47b7ea130cf21e5e1d42b", size = 15685197, upload-time = "2026-05-18T23:35:50.863Z" }, + { url = "https://files.pythonhosted.org/packages/f3/eb/ebffaa97dc55502df69584a8f0dcf07f69a3e0b3e2323670a2722db9aa39/numpy-2.4.6-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a2c306dea656c12c68f51f4cea133cbe78ca7435eb28c735eac1d3ebe73be6e8", size = 16638245, upload-time = "2026-05-18T23:35:54.752Z" }, + { url = "https://files.pythonhosted.org/packages/b8/0b/54f9da33128d7e350fab89c7455902eeae70349ee52bddb448dc4a576f45/numpy-2.4.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:33111801a01c12a8a1e3721f0a9232f8cfc8ae2c6b7098167e6f623c6073f402", size = 17036587, upload-time = "2026-05-18T23:35:58.355Z" }, + { url = "https://files.pythonhosted.org/packages/b6/f0/fdebc1052db1cc37c64beb22072d67cd6d1c71adca1299f53dec2b5e20d3/numpy-2.4.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ae506e6902902557576a26ff33eda8695e7ecb3cb36c3b573a0765dee114ebdb", size = 18363226, upload-time = "2026-05-18T23:36:02.845Z" }, + { url = "https://files.pythonhosted.org/packages/aa/b4/298628d98c72b57e57f7165ae6a481a1deaf6f3c28262a6e4c739c275930/numpy-2.4.6-cp314-cp314-win32.whl", hash = "sha256:aaf159caa35993cb1f56fb9b8e4610d35758e7ca005412eb1daa856a78c9c4b1", size = 6010196, upload-time = "2026-05-18T23:36:05.92Z" }, + { url = "https://files.pythonhosted.org/packages/df/ac/46de6dda46478f7942f839e094970be2d4a861e005c4b3bf07c92e291a09/numpy-2.4.6-cp314-cp314-win_amd64.whl", hash = "sha256:b507f5c4c1d508876d1819b6bf9a49d365b96320b5d4993426b33a23ca4b8261", size = 12450334, upload-time = "2026-05-18T23:36:09.107Z" }, + { url = "https://files.pythonhosted.org/packages/78/92/b8b798ac784102c0da830d2257d59358e3d3d90d1e2b3f2575dad976c5cf/numpy-2.4.6-cp314-cp314-win_arm64.whl", hash = "sha256:6f41ae150c4e32db4f3310cdaf64b1593a03dbabe29eec77fc9b50fe64061df6", size = 10495678, upload-time = "2026-05-18T23:36:12.766Z" }, + { url = "https://files.pythonhosted.org/packages/30/34/ec28d1aa8115971537c01469ab2011ee96827930f0a124de1000cc2a7ed7/numpy-2.4.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ece3d2cfe132e7d51f44a832b303895e6f2d499c5e74dfbdb06ee246147a304a", size = 14823672, upload-time = "2026-05-18T23:36:16.473Z" }, + { url = "https://files.pythonhosted.org/packages/16/bd/f6d1fede4e54e8042a7ff97bb495510f3c220f94bcd9e8b228e87c92cc0d/numpy-2.4.6-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:e3e5193ef5a3dc73bceee50f7fdc2c90dbb76c42df8d8fae3d1067a583df579e", size = 5328731, upload-time = "2026-05-18T23:36:19.767Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f0/e105b9e2fd728a9910103884decd6951d9dd73896b914a98d9a231de02ee/numpy-2.4.6-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:17f9ade344e7d9b464a084d69bcf18fc691cb1db67c62ed80820bf4926d78f0e", size = 6649805, upload-time = "2026-05-18T23:36:22.266Z" }, + { url = "https://files.pythonhosted.org/packages/82/dd/1206a7ca6ab15e3f02069707ca96222e202af681bb73756da7527f3cb837/numpy-2.4.6-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cd5ffd25db4e7ba6a375693b3fc0fc1791ec636c17db3720da19bde7180ec43", size = 15730496, upload-time = "2026-05-18T23:36:25.713Z" }, + { url = "https://files.pythonhosted.org/packages/51/e7/38d3ea825dcab85a591734decb2f6c67caa7c8367d374df1a1c3842f9b07/numpy-2.4.6-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d92c3819208a60205a12a245c91ad70cb0a85336659b19b834205573ac8456e", size = 16679616, upload-time = "2026-05-18T23:36:29.652Z" }, + { url = "https://files.pythonhosted.org/packages/93/b7/caabfdf53edf663e0b4eb74d7d405d83baef09eb5e83bcd32d601d72b93e/numpy-2.4.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e85b752a1e912b70eaad4fafbd4d1238007ab221de2009b9a2f5ae7461239895", size = 17085145, upload-time = "2026-05-18T23:36:33.449Z" }, + { url = "https://files.pythonhosted.org/packages/f9/45/68d7c33a6bcf3e5aa3bdbd57a367e6f615286dfd6482f97e8ffeb734306e/numpy-2.4.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:29cb7f67d10b479ff07c17d33e39f78c07f71c40ef30d63c153d340e96cd3fb4", size = 18403813, upload-time = "2026-05-18T23:36:37.369Z" }, + { url = "https://files.pythonhosted.org/packages/9c/50/0753655aa844c99cd9e018aacf76f130f1bd81d881bb74bc0aef5d73a8ba/numpy-2.4.6-cp314-cp314t-win32.whl", hash = "sha256:260a5d70215b61ab4fadf5c7baacd64821842975eea312125ed3c39a6391b063", size = 6156982, upload-time = "2026-05-18T23:36:40.817Z" }, + { url = "https://files.pythonhosted.org/packages/b2/d4/7c67becf668f973cb490cec3e98dfd799d866f9c989a54d355672cfa0db6/numpy-2.4.6-cp314-cp314t-win_amd64.whl", hash = "sha256:81a1cca95ed5bb92aa8b10dd2cdc9a0d3853a50fad926c28b5d7e8ea54389627", size = 12638908, upload-time = "2026-05-18T23:36:43.996Z" }, + { url = "https://files.pythonhosted.org/packages/43/bb/e1c71a4295b1b1d1393d50dbb4f2a36283c6859d9d3892e84f00ec5a91d5/numpy-2.4.6-cp314-cp314t-win_arm64.whl", hash = "sha256:0c9136e14ed34a9e343a31c533d78a9813a69a3148332bce5e9821cb2f996e66", size = 10565867, upload-time = "2026-05-18T23:36:47.114Z" }, + { url = "https://files.pythonhosted.org/packages/de/12/b422cc84439adc0d00de605bf4a308890ae5c26f2c71fbd73e5d08fbb0dd/numpy-2.4.6-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:55cced7c52e981362f708ad635198e97a752dfba412cc03c23bbf3bd8d5cd662", size = 16847511, upload-time = "2026-05-18T23:36:50.673Z" }, + { url = "https://files.pythonhosted.org/packages/44/53/f481bef68011740f8849418d82db07230e825013f31f4eef5ba5b805316a/numpy-2.4.6-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d6da64deb6b8ed903e7560180a92f2d804ee1ba5eeb849ac2748b8c1aba1f6d7", size = 14889064, upload-time = "2026-05-18T23:36:53.879Z" }, + { url = "https://files.pythonhosted.org/packages/7f/57/42ed575c10ced8af951d426bc4e1f8aff16fd851db33f067036215a7f860/numpy-2.4.6-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:68a5124b13fa6cc2086764a20005d30bc0548146f7f5322f02fce212ca14317f", size = 5394157, upload-time = "2026-05-18T23:36:57.194Z" }, + { url = "https://files.pythonhosted.org/packages/6a/ef/f66cc724fcc36c1e364c67f51ae9146090b8b584f27d58b97fdae3edd737/numpy-2.4.6-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:948424b06129ce883307e8cff868c31396d8dc7630a59c61d70d98dbe70f222c", size = 6708728, upload-time = "2026-05-18T23:36:59.575Z" }, + { url = "https://files.pythonhosted.org/packages/1a/9c/c531f2293b91265d8b48e9b329f54fdd7ffae73cb4134ea10cca4237e9cc/numpy-2.4.6-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5dbbdb29840ca3d91ee0fece42fc29278886d908280bfec0a5846c6f901a3eb0", size = 15798374, upload-time = "2026-05-18T23:37:02.674Z" }, + { url = "https://files.pythonhosted.org/packages/1a/b0/413077f6b1153ed3cba361401c6783bbad6114804a000cc22eb71c13e190/numpy-2.4.6-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8ad03c0965fb3c692200e74d458ca28c1dbb4ce96f9a479a8aa041ad5fabca02", size = 16747286, upload-time = "2026-05-18T23:37:06.327Z" }, + { url = "https://files.pythonhosted.org/packages/15/ce/e5ec180bc41812edcd8daeb8639d205622c0e8c02259d8ab25a0201b3c2a/numpy-2.4.6-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:2803abfebfc990042cd494d8ce2d5f82e9d847af6d35ec486923aa19dbad5e73", size = 12504263, upload-time = "2026-05-18T23:37:09.715Z" }, +] + +[[package]] +name = "openai" +version = "2.38.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "httpx" }, + { name = "jiter" }, + { name = "pydantic" }, + { name = "sniffio" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8f/12/cfa322c5f5dd8fa21aab9a7a8e979e7a11123800f86ca8d82eb68a83d213/openai-2.38.0.tar.gz", hash = "sha256:798694c6cf74145541fda94325b6f8f72d8e1fd0262cc137c8d728177a6a4ce3", size = 772764, upload-time = "2026-05-21T21:23:42.105Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/bf/ccff9be562e24207716d04ef9dc931c76aff0c89a7265da43e2104d7fe06/openai-2.38.0-py3-none-any.whl", hash = "sha256:ec6661c57b2dcc47414a767e6e3335c7ed3d19c9696999283a3c82e95c756a3c", size = 1344910, upload-time = "2026-05-21T21:23:39.636Z" }, +] + +[[package]] +name = "packaging" +version = "26.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, +] + +[[package]] +name = "pandas" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "python-dateutil" }, + { name = "tzdata", marker = "sys_platform == 'emscripten' or sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f8/87/4341c6252d1c47b08768c3d25ac487362bf403f0313ddae4a2a26c9b1b4c/pandas-3.0.3.tar.gz", hash = "sha256:696a4a00a2a2a35d4e5deb3fc946641b96c944f02230e4f76137fe35d806c4fc", size = 4651414, upload-time = "2026-05-11T18:54:29.21Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/16/b5c76b838fd9bf6ce84d3a53346b8874ec05c5f0040d75ef2c320100cd2a/pandas-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:455f6f8139d4282188f526868dbc3c828470e88a3d9d59a891bd46a455f21b98", size = 10338495, upload-time = "2026-05-11T18:52:11.558Z" }, + { url = "https://files.pythonhosted.org/packages/5a/b0/a4ffc4ae74d2d822200dcc46898987d8eb6032d1e2b219cae39da6f5cbcc/pandas-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4e15135e2ee5df1063313e2425ceef8ac0f4ae775893815b0923651b806a5639", size = 9938250, upload-time = "2026-05-11T18:52:17.005Z" }, + { url = "https://files.pythonhosted.org/packages/2e/b2/3323601a52caee42c019e370090ca4544b241437240ca04f786cce82b0cf/pandas-3.0.3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:05f1f1752b8533ea03f7f39a9c15b1a058d067bb48f4748948e7a8691e0510f2", size = 10770558, upload-time = "2026-05-11T18:52:19.865Z" }, + { url = "https://files.pythonhosted.org/packages/32/f1/bbecd2f867b97abebe0f9b53d750f862251b40337e061b36676ded3d920f/pandas-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a1e45c80cceb3b4a21bc5939d52e8cbd8d9b7305309219d59e9754d9ce09e27", size = 11274611, upload-time = "2026-05-11T18:52:22.622Z" }, + { url = "https://files.pythonhosted.org/packages/7f/4f/eafabf2d5fae5adf143b4d18d3706c5efdc368a7c4eb1ee8a3eddabbd0f6/pandas-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:14da8316da4d0c5a77618425996bfb1248ca87fc2c1486e6fde4652bd18b5824", size = 11784670, upload-time = "2026-05-11T18:52:25.4Z" }, + { url = "https://files.pythonhosted.org/packages/49/44/1eb20389301b57b19cc099a1c2f662501f72f08a65f912d05822613c1532/pandas-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a55066a0505dae0ba2b50a46637db34b46f9094c65c5d4800794ef6335010938", size = 12353708, upload-time = "2026-05-11T18:52:28.139Z" }, + { url = "https://files.pythonhosted.org/packages/eb/62/c321f13b5ba1819fc8dca456c7fce578da2dcfecff1abbf0eaddf8406c0f/pandas-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:6674ab18ad8c57802867264b00e15e7bb904700cdd9046e3b2fa1fce237439ea", size = 9907609, upload-time = "2026-05-11T18:52:30.982Z" }, + { url = "https://files.pythonhosted.org/packages/53/85/1b7f563ebc6357c27233a02a96b589bcce1fa9c6eb89fb4f0e56421d277e/pandas-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:5cc09a68b3120e0f54870dede8287a7bb1fa463907e4fcec1ea77cab6179bf7a", size = 9165596, upload-time = "2026-05-11T18:52:33.334Z" }, + { url = "https://files.pythonhosted.org/packages/24/f1/392f8c5bfc16f66a0d2d41561c01627c228fe7ed2a0d056ef11315042570/pandas-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fed2ff7fd9779120e388e285fc029bd5cf9490cdd2e4166a9ee22c0e49a9ab09", size = 10357846, upload-time = "2026-05-11T18:52:36.143Z" }, + { url = "https://files.pythonhosted.org/packages/cf/3d/b16412745651e855f357e5e66930248688378853a6e2698a214e331fba1f/pandas-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b168fc218fd80a6cbdbdbc1a97ddc7889ed057d7eb45f50d866ceab5f39904c4", size = 9899550, upload-time = "2026-05-11T18:52:38.976Z" }, + { url = "https://files.pythonhosted.org/packages/31/a8/fa2535168fffcedf67f4f6de28d2dd903a747ca7c8ea6989451aaeb3a92f/pandas-3.0.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0383c72c75cdcca61a9e116e611143902dbfd08bff356829c2f6d1cf40a9ca8c", size = 10412965, upload-time = "2026-05-11T18:52:41.915Z" }, + { url = "https://files.pythonhosted.org/packages/65/b6/09b01cdbc15224e2850365192d17b7bdebb8bdbd8780ed221fcdf0d9a515/pandas-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6dc0b3fd2169c9157deed50b4d519553a3655c8c6a96027136d654592be973a9", size = 10894600, upload-time = "2026-05-11T18:52:45.02Z" }, + { url = "https://files.pythonhosted.org/packages/c9/a4/2eb28f2fccb4ced4a2c79ab2a5dee9ade1ebf44922ebad6fea158c9f95d4/pandas-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7e65d5407dc0b394f509699650e4a2ec01c0514f21850f453fa60f3be79a5dbf", size = 11422824, upload-time = "2026-05-11T18:52:48.058Z" }, + { url = "https://files.pythonhosted.org/packages/f8/45/830bb57f533a4604b355e07edcb8ea18cf88b5f94e5fca92f27052d7c597/pandas-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f8894dc474d648fe7b6ff0ca9b0bd73950d19952bc1a6534540762c5d79d305c", size = 11950889, upload-time = "2026-05-11T18:52:50.905Z" }, + { url = "https://files.pythonhosted.org/packages/b9/c5/fc1b368f303087d20e8c9bf3d6ceb186263cfac0ade735cd938538bea839/pandas-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:c7be265b62cef88e253a941e4698604973736dcfe242fdb5198f0f7bc473cdcc", size = 9755463, upload-time = "2026-05-11T18:52:53.386Z" }, + { url = "https://files.pythonhosted.org/packages/86/bd/fda8f9705b1b09c6ebe14bfc0fa0e4ec8584d54ea673628f157ff55131af/pandas-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:557409bc4178e70ee8d9ddb494798e51ebf6ea59330f6be22c51bab2a7db6c49", size = 9066158, upload-time = "2026-05-11T18:52:56.038Z" }, + { url = "https://files.pythonhosted.org/packages/c5/90/62d8302883c44308c477e222c3daf7c813a34c8e96985882fbd53d964352/pandas-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:67b3b64c11910cfa29f4e94a14d3bff9ee693b6fc76055e7cad549cee0aec5fa", size = 10331071, upload-time = "2026-05-11T18:52:58.838Z" }, + { url = "https://files.pythonhosted.org/packages/7f/ae/6a6493c783a101f165e4356953ba3c74d6f77f0042fa7d753da9dfbb640c/pandas-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:39436b377d56d2a2e52d0395bdbee171f01068e99af5250509aceeb929f765c7", size = 9875690, upload-time = "2026-05-11T18:53:01.431Z" }, + { url = "https://files.pythonhosted.org/packages/62/7c/5df8e9f56c69a2769fbe9382a5ef8f2658c007e376434e1e2cbb57ad895f/pandas-3.0.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4be06d68f9ddcfc645b87534911da79a8fbffc7573c80e0edcf42a5020624d8", size = 10381634, upload-time = "2026-05-11T18:53:04.393Z" }, + { url = "https://files.pythonhosted.org/packages/99/68/1237369725aa617bb358263d535803e3053fdbc593513ec5ed9c9896b5b6/pandas-3.0.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a4eeb6830daf35a71cc09649bd823e2b542dac246cdee9614c6e4bd65028cd6a", size = 10891243, upload-time = "2026-05-11T18:53:07.643Z" }, + { url = "https://files.pythonhosted.org/packages/25/93/77d108e8af7222b4a503ebde0e30215b1c2e4f8e53a526431890f22d5586/pandas-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1928e07221f82db493cd4af1e23c1bfca524a19a4699887975bff68f49a72bfb", size = 11388659, upload-time = "2026-05-11T18:53:10.634Z" }, + { url = "https://files.pythonhosted.org/packages/d0/bd/eff5b4399f332ac386c853f6cd2bd3fa2ca0061b9f36ecd9c4d7c4265649/pandas-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51b1fe551acb77dac643c6fda86084d8d446c10fe64b06a9cc29c4cc8540e7f2", size = 11942880, upload-time = "2026-05-11T18:53:13.536Z" }, + { url = "https://files.pythonhosted.org/packages/2c/20/559ace4200982c3887d0b86bfd0d856a2143ef8ddab63cc07934951a964c/pandas-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:a82d532a3351d435432cd913edbccaf8b8e01d4dd0e5ced5a8d2e8ecd94c7e44", size = 9757091, upload-time = "2026-05-11T18:53:16.306Z" }, + { url = "https://files.pythonhosted.org/packages/3a/66/69055a09fe200f29f922a3eeec4804611900b95f52d932ece3393c3c0c19/pandas-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:275c14e0fce14a2ec20eee474aecd305478ea3c1e6f6a9d8fe219a165542717e", size = 9057282, upload-time = "2026-05-11T18:53:18.768Z" }, + { url = "https://files.pythonhosted.org/packages/57/0e/efe801b0e6811e8e650cd21b7f2608e30f08a7067e2bf6e8752b0d56ee3c/pandas-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:46997386d528eb40376ecd6b033cf4a8a1e5282580f68f43de875b78cba2199d", size = 10767016, upload-time = "2026-05-11T18:53:21.227Z" }, + { url = "https://files.pythonhosted.org/packages/ea/dc/eb55135a1d5f0f0519f28da1f609a206d2cad1f9c35c32d51e38dd7261ae/pandas-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:261e308dfb22448384b7580cf719d2f998fe2966c92893c3e77d14008af1f066", size = 10420210, upload-time = "2026-05-11T18:53:23.982Z" }, + { url = "https://files.pythonhosted.org/packages/c6/3e/b1d5d955ce33ffecb407465a60bc32769d74fcf68224b7ae67ae11d4dea4/pandas-3.0.3-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dd1a5d1def6a46002e964510bdc67c368aa0951df5d1d9f8365336f5a1f490cd", size = 10336126, upload-time = "2026-05-11T18:53:26.731Z" }, + { url = "https://files.pythonhosted.org/packages/f5/76/a01261711ab60a22d71b862f0de20e4c504bf80457270ad8cb42110f6abc/pandas-3.0.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d72828c20c6d6e83e1e22a6a3b47b326b71664112fa9705dcbccfd7a39b62085", size = 10728051, upload-time = "2026-05-11T18:53:29.125Z" }, + { url = "https://files.pythonhosted.org/packages/e9/21/ea191195e587b18cf682e97f433f81b2d0fbe341380e80a3e0d6e4403c8e/pandas-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d26cbe1fcfc12e8fd900e2454163e466b2d3af84f7c75481df7683ffc073d870", size = 11350796, upload-time = "2026-05-11T18:53:32.056Z" }, + { url = "https://files.pythonhosted.org/packages/64/69/f0eaaf54939f0e8c6768fd06be9af2cef9b36048b96dfb9e1b2c685a807e/pandas-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3e91cec1879ada0624fc3dc9953c5cbd60208e59c0db28f540c5d6d47502422f", size = 11799741, upload-time = "2026-05-11T18:53:34.985Z" }, + { url = "https://files.pythonhosted.org/packages/45/a4/865e0e510cae5fc2194de4db28be638952de942571ba9125934fd9c01d47/pandas-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:08d789b41f87e0905880e293cedf6197ce71fe67cc081358b1e148a491b9bd13", size = 10499958, upload-time = "2026-05-11T18:53:37.857Z" }, + { url = "https://files.pythonhosted.org/packages/86/54/effdcc3c0ff7a08037889200e148ebe94c16c4f653be078c7b3675955df1/pandas-3.0.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:3650109c0f22879df8bd6179ab9ee3d7f1d1d4e7e0094a3f0032d9f51e2e64ac", size = 10336065, upload-time = "2026-05-11T18:53:41.099Z" }, + { url = "https://files.pythonhosted.org/packages/68/10/bf2d6738d72748b961a3751ab89522d58c54efc36a8e1a12161216cd45cf/pandas-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:bab900348131a7db1f69a7309ef141fd5680f1487094193bcbbb61791573bf8f", size = 9926101, upload-time = "2026-05-11T18:53:43.515Z" }, + { url = "https://files.pythonhosted.org/packages/ae/e9/e35cf11c8a136e757b956f5f0efdcaa50aecde85ea055f1898dfc68262f3/pandas-3.0.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba7e08b9ac1d54569cd1e256e3668975ed624d6826f7b68df0342b012007bddb", size = 10457553, upload-time = "2026-05-11T18:53:46.394Z" }, + { url = "https://files.pythonhosted.org/packages/58/3b/1cdec6772bdbaf7b25dab360c59f03cadf05492dd724c6540af905389b07/pandas-3.0.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d71c63ae4ebdbf70209742096f1fc46a83a0613c99d4b23766cced9ff8cd62a", size = 10914065, upload-time = "2026-05-11T18:53:49.134Z" }, + { url = "https://files.pythonhosted.org/packages/c4/c2/1ef644445fcd72e3627bceec77e3560636f87ddce4ed841afe76b83b5bf9/pandas-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e3a2ec42c98ffa2565a67e08e218d06d72576d758d90facb7c00805194d8f360", size = 11459188, upload-time = "2026-05-11T18:53:52.527Z" }, + { url = "https://files.pythonhosted.org/packages/7e/49/4d8d4f42cbc9c4adc7a1870f269c02cbd6cd40d059622c06fb298addcbad/pandas-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:335f62418ed562cfc3c49e9e196375c28b729dcef8543abf4f9438e381bf3c76", size = 11982966, upload-time = "2026-05-11T18:53:55.043Z" }, + { url = "https://files.pythonhosted.org/packages/38/55/792619469bab9882d8bbd5865d45a72f6478762d04a9af4bf0d08c503e95/pandas-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:3c20a521bbb85902f79f7270c80a59e1b5452d96d170c034f207181870f97ac5", size = 9876755, upload-time = "2026-05-11T18:53:58.067Z" }, + { url = "https://files.pythonhosted.org/packages/2a/af/33c469653b0ba03b50c3a98192d4c07f0c75c66b263ceb097fce0ee97d31/pandas-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:a2d2dff8a04f3917b55ab3910c32990f8ddf7eceba114947838cefa976a68977", size = 9198658, upload-time = "2026-05-11T18:54:00.733Z" }, + { url = "https://files.pythonhosted.org/packages/a2/fa/b8c257bd76b8bd060c3a9151c1fca05e9b9c5e3af5d0f549c0356f6d143d/pandas-3.0.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:0d589105b3c14645af1738ff279b2995102d8f7a03b0a66dc8d95550eb513e04", size = 10787242, upload-time = "2026-05-11T18:54:03.564Z" }, + { url = "https://files.pythonhosted.org/packages/54/eb/f19206ffb0bf1919002969aa448b4702c6594845156a6f8050674855aac3/pandas-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:13fc1e853d9e04743d11ba75a985ccbc2a317fe07d8af61e445a6fd24dacd6a6", size = 10436369, upload-time = "2026-05-11T18:54:06.311Z" }, + { url = "https://files.pythonhosted.org/packages/fd/24/c7c39fb4fe22b71a0c2d78bf0c585c600092d85f94f086d2b3b2f6ca27e2/pandas-3.0.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:819959dab7bbd0049c15623fbac4e29a191b9528160a61fb1032242d8ced2d9c", size = 10358306, upload-time = "2026-05-11T18:54:09.085Z" }, + { url = "https://files.pythonhosted.org/packages/16/ec/dd2a9eb7fa1204df88c0864164e35b228ac581062ac612ba0a67fd812e4c/pandas-3.0.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:60ae316d3fd75d1858d450d0db0103ea2be3e7d4a95ec2f064f7e2ae63f7b028", size = 10758394, upload-time = "2026-05-11T18:54:11.956Z" }, + { url = "https://files.pythonhosted.org/packages/95/6e/00c61ea8e85b4f6d8d35e11852a1a4998fc7fafc91c6a602d1cc9c972d64/pandas-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bd3a518890b400d32f9023722dc9a9a5c969f00b415419a3c06c043f09bb5d7d", size = 11375717, upload-time = "2026-05-11T18:54:14.539Z" }, + { url = "https://files.pythonhosted.org/packages/31/89/8fc1c268969fac43688d65fd92e67df24bd128d53cb4d2eee534cd307399/pandas-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9c39be2d709d01fa972a0cabc522389fceca4f3969332ba25a7d6c5802cf976a", size = 11828897, upload-time = "2026-05-11T18:54:17.146Z" }, + { url = "https://files.pythonhosted.org/packages/56/3b/e7d20dea247a3e6dc0bd8a6953854afbedc03951def4e7371e05e7263e25/pandas-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4db8c527972a821cf5286b40ccc57642a39bc62e62022b42f99f8a67fca8c3a1", size = 10900855, upload-time = "2026-05-11T18:54:19.72Z" }, + { url = "https://files.pythonhosted.org/packages/0f/54/68a0978d1ef8502b8492099beaa6e7a0c1b32e3b5d4f677f5810cb08711c/pandas-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:b2c95f8bfc1ee412bf482605d7bfd30c12d1d26bd59fdd91efeef1d4718decb1", size = 9466464, upload-time = "2026-05-11T18:54:22.754Z" }, +] + +[[package]] +name = "parso" +version = "0.8.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/4b/90c937815137d43ce71ba043cd3566221e9df6b9c805f24b5d138c9d40a7/parso-0.8.7.tar.gz", hash = "sha256:eaaac4c9fdd5e9e8852dc778d2d7405897ec510f2a298071453e5e3a07914bb1", size = 401824, upload-time = "2026-05-01T23:13:02.138Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/5d/8268b644392ee874ee82a635cd0df1773de230bde356c38de28e298392cc/parso-0.8.7-py2.py3-none-any.whl", hash = "sha256:a8926eb2a1b915486941fdbd31e86a4baf88fe8c210f25f2f35ecec5b574ca1c", size = 107025, upload-time = "2026-05-01T23:12:58.867Z" }, +] + +[[package]] +name = "pathspec" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" }, +] + +[[package]] +name = "pexpect" +version = "4.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ptyprocess", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, +] + +[[package]] +name = "pillow" +version = "12.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/21/c2bcdd5906101a30244eaffc1b6e6ce71a31bd0742a01eb89e660ebfac2d/pillow-12.2.0.tar.gz", hash = "sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5", size = 46987819, upload-time = "2026-04-01T14:46:17.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/68/e1/748f5663efe6edcfc4e74b2b93edfb9b8b99b67f21a854c3ae416500a2d9/pillow-12.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:8be29e59487a79f173507c30ddf57e733a357f67881430449bb32614075a40ab", size = 5354347, upload-time = "2026-04-01T14:42:44.255Z" }, + { url = "https://files.pythonhosted.org/packages/47/a1/d5ff69e747374c33a3b53b9f98cca7889fce1fd03d79cdc4e1bccc6c5a87/pillow-12.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:71cde9a1e1551df7d34a25462fc60325e8a11a82cc2e2f54578e5e9a1e153d65", size = 4695873, upload-time = "2026-04-01T14:42:46.452Z" }, + { url = "https://files.pythonhosted.org/packages/df/21/e3fbdf54408a973c7f7f89a23b2cb97a7ef30c61ab4142af31eee6aebc88/pillow-12.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f490f9368b6fc026f021db16d7ec2fbf7d89e2edb42e8ec09d2c60505f5729c7", size = 6280168, upload-time = "2026-04-01T14:42:49.228Z" }, + { url = "https://files.pythonhosted.org/packages/d3/f1/00b7278c7dd52b17ad4329153748f87b6756ec195ff786c2bdf12518337d/pillow-12.2.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8bd7903a5f2a4545f6fd5935c90058b89d30045568985a71c79f5fd6edf9b91e", size = 8088188, upload-time = "2026-04-01T14:42:51.735Z" }, + { url = "https://files.pythonhosted.org/packages/ad/cf/220a5994ef1b10e70e85748b75649d77d506499352be135a4989c957b701/pillow-12.2.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3997232e10d2920a68d25191392e3a4487d8183039e1c74c2297f00ed1c50705", size = 6394401, upload-time = "2026-04-01T14:42:54.343Z" }, + { url = "https://files.pythonhosted.org/packages/e9/bd/e51a61b1054f09437acfbc2ff9106c30d1eb76bc1453d428399946781253/pillow-12.2.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e74473c875d78b8e9d5da2a70f7099549f9eb37ded4e2f6a463e60125bccd176", size = 7079655, upload-time = "2026-04-01T14:42:56.954Z" }, + { url = "https://files.pythonhosted.org/packages/6b/3d/45132c57d5fb4b5744567c3817026480ac7fc3ce5d4c47902bc0e7f6f853/pillow-12.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:56a3f9c60a13133a98ecff6197af34d7824de9b7b38c3654861a725c970c197b", size = 6503105, upload-time = "2026-04-01T14:42:59.847Z" }, + { url = "https://files.pythonhosted.org/packages/7d/2e/9df2fc1e82097b1df3dce58dc43286aa01068e918c07574711fcc53e6fb4/pillow-12.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:90e6f81de50ad6b534cab6e5aef77ff6e37722b2f5d908686f4a5c9eba17a909", size = 7203402, upload-time = "2026-04-01T14:43:02.664Z" }, + { url = "https://files.pythonhosted.org/packages/bd/2e/2941e42858ebb67e50ae741473de81c2984e6eff7b397017623c676e2e8d/pillow-12.2.0-cp311-cp311-win32.whl", hash = "sha256:8c984051042858021a54926eb597d6ee3012393ce9c181814115df4c60b9a808", size = 6378149, upload-time = "2026-04-01T14:43:05.274Z" }, + { url = "https://files.pythonhosted.org/packages/69/42/836b6f3cd7f3e5fa10a1f1a5420447c17966044c8fbf589cc0452d5502db/pillow-12.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e6b2a0c538fc200b38ff9eb6628228b77908c319a005815f2dde585a0664b60", size = 7082626, upload-time = "2026-04-01T14:43:08.557Z" }, + { url = "https://files.pythonhosted.org/packages/c2/88/549194b5d6f1f494b485e493edc6693c0a16f4ada488e5bd974ed1f42fad/pillow-12.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:9a8a34cc89c67a65ea7437ce257cea81a9dad65b29805f3ecee8c8fe8ff25ffe", size = 2463531, upload-time = "2026-04-01T14:43:10.743Z" }, + { url = "https://files.pythonhosted.org/packages/58/be/7482c8a5ebebbc6470b3eb791812fff7d5e0216c2be3827b30b8bb6603ed/pillow-12.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2d192a155bbcec180f8564f693e6fd9bccff5a7af9b32e2e4bf8c9c69dbad6b5", size = 5308279, upload-time = "2026-04-01T14:43:13.246Z" }, + { url = "https://files.pythonhosted.org/packages/d8/95/0a351b9289c2b5cbde0bacd4a83ebc44023e835490a727b2a3bd60ddc0f4/pillow-12.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3f40b3c5a968281fd507d519e444c35f0ff171237f4fdde090dd60699458421", size = 4695490, upload-time = "2026-04-01T14:43:15.584Z" }, + { url = "https://files.pythonhosted.org/packages/de/af/4e8e6869cbed569d43c416fad3dc4ecb944cb5d9492defaed89ddd6fe871/pillow-12.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:03e7e372d5240cc23e9f07deca4d775c0817bffc641b01e9c3af208dbd300987", size = 6284462, upload-time = "2026-04-01T14:43:18.268Z" }, + { url = "https://files.pythonhosted.org/packages/e9/9e/c05e19657fd57841e476be1ab46c4d501bffbadbafdc31a6d665f8b737b6/pillow-12.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b86024e52a1b269467a802258c25521e6d742349d760728092e1bc2d135b4d76", size = 8094744, upload-time = "2026-04-01T14:43:20.716Z" }, + { url = "https://files.pythonhosted.org/packages/2b/54/1789c455ed10176066b6e7e6da1b01e50e36f94ba584dc68d9eebfe9156d/pillow-12.2.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7371b48c4fa448d20d2714c9a1f775a81155050d383333e0a6c15b1123dda005", size = 6398371, upload-time = "2026-04-01T14:43:23.443Z" }, + { url = "https://files.pythonhosted.org/packages/43/e3/fdc657359e919462369869f1c9f0e973f353f9a9ee295a39b1fea8ee1a77/pillow-12.2.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62f5409336adb0663b7caa0da5c7d9e7bdbaae9ce761d34669420c2a801b2780", size = 7087215, upload-time = "2026-04-01T14:43:26.758Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f8/2f6825e441d5b1959d2ca5adec984210f1ec086435b0ed5f52c19b3b8a6e/pillow-12.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:01afa7cf67f74f09523699b4e88c73fb55c13346d212a59a2db1f86b0a63e8c5", size = 6509783, upload-time = "2026-04-01T14:43:29.56Z" }, + { url = "https://files.pythonhosted.org/packages/67/f9/029a27095ad20f854f9dba026b3ea6428548316e057e6fc3545409e86651/pillow-12.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc3d34d4a8fbec3e88a79b92e5465e0f9b842b628675850d860b8bd300b159f5", size = 7212112, upload-time = "2026-04-01T14:43:32.091Z" }, + { url = "https://files.pythonhosted.org/packages/be/42/025cfe05d1be22dbfdb4f264fe9de1ccda83f66e4fc3aac94748e784af04/pillow-12.2.0-cp312-cp312-win32.whl", hash = "sha256:58f62cc0f00fd29e64b29f4fd923ffdb3859c9f9e6105bfc37ba1d08994e8940", size = 6378489, upload-time = "2026-04-01T14:43:34.601Z" }, + { url = "https://files.pythonhosted.org/packages/5d/7b/25a221d2c761c6a8ae21bfa3874988ff2583e19cf8a27bf2fee358df7942/pillow-12.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:7f84204dee22a783350679a0333981df803dac21a0190d706a50475e361c93f5", size = 7084129, upload-time = "2026-04-01T14:43:37.213Z" }, + { url = "https://files.pythonhosted.org/packages/10/e1/542a474affab20fd4a0f1836cb234e8493519da6b76899e30bcc5d990b8b/pillow-12.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:af73337013e0b3b46f175e79492d96845b16126ddf79c438d7ea7ff27783a414", size = 2463612, upload-time = "2026-04-01T14:43:39.421Z" }, + { url = "https://files.pythonhosted.org/packages/4a/01/53d10cf0dbad820a8db274d259a37ba50b88b24768ddccec07355382d5ad/pillow-12.2.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:8297651f5b5679c19968abefd6bb84d95fe30ef712eb1b2d9b2d31ca61267f4c", size = 4100837, upload-time = "2026-04-01T14:43:41.506Z" }, + { url = "https://files.pythonhosted.org/packages/0f/98/f3a6657ecb698c937f6c76ee564882945f29b79bad496abcba0e84659ec5/pillow-12.2.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:50d8520da2a6ce0af445fa6d648c4273c3eeefbc32d7ce049f22e8b5c3daecc2", size = 4176528, upload-time = "2026-04-01T14:43:43.773Z" }, + { url = "https://files.pythonhosted.org/packages/69/bc/8986948f05e3ea490b8442ea1c1d4d990b24a7e43d8a51b2c7d8b1dced36/pillow-12.2.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:766cef22385fa1091258ad7e6216792b156dc16d8d3fa607e7545b2b72061f1c", size = 3640401, upload-time = "2026-04-01T14:43:45.87Z" }, + { url = "https://files.pythonhosted.org/packages/34/46/6c717baadcd62bc8ed51d238d521ab651eaa74838291bda1f86fe1f864c9/pillow-12.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5d2fd0fa6b5d9d1de415060363433f28da8b1526c1c129020435e186794b3795", size = 5308094, upload-time = "2026-04-01T14:43:48.438Z" }, + { url = "https://files.pythonhosted.org/packages/71/43/905a14a8b17fdb1ccb58d282454490662d2cb89a6bfec26af6d3520da5ec/pillow-12.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56b25336f502b6ed02e889f4ece894a72612fe885889a6e8c4c80239ff6e5f5f", size = 4695402, upload-time = "2026-04-01T14:43:51.292Z" }, + { url = "https://files.pythonhosted.org/packages/73/dd/42107efcb777b16fa0393317eac58f5b5cf30e8392e266e76e51cff28c3d/pillow-12.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f1c943e96e85df3d3478f7b691f229887e143f81fedab9b20205349ab04d73ed", size = 6280005, upload-time = "2026-04-01T14:43:54.242Z" }, + { url = "https://files.pythonhosted.org/packages/a8/68/b93e09e5e8549019e61acf49f65b1a8530765a7f812c77a7461bca7e4494/pillow-12.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:03f6fab9219220f041c74aeaa2939ff0062bd5c364ba9ce037197f4c6d498cd9", size = 8090669, upload-time = "2026-04-01T14:43:57.335Z" }, + { url = "https://files.pythonhosted.org/packages/4b/6e/3ccb54ce8ec4ddd1accd2d89004308b7b0b21c4ac3d20fa70af4760a4330/pillow-12.2.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cdfebd752ec52bf5bb4e35d9c64b40826bc5b40a13df7c3cda20a2c03a0f5ed", size = 6395194, upload-time = "2026-04-01T14:43:59.864Z" }, + { url = "https://files.pythonhosted.org/packages/67/ee/21d4e8536afd1a328f01b359b4d3997b291ffd35a237c877b331c1c3b71c/pillow-12.2.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eedf4b74eda2b5a4b2b2fb4c006d6295df3bf29e459e198c90ea48e130dc75c3", size = 7082423, upload-time = "2026-04-01T14:44:02.74Z" }, + { url = "https://files.pythonhosted.org/packages/78/5f/e9f86ab0146464e8c133fe85df987ed9e77e08b29d8d35f9f9f4d6f917ba/pillow-12.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:00a2865911330191c0b818c59103b58a5e697cae67042366970a6b6f1b20b7f9", size = 6505667, upload-time = "2026-04-01T14:44:05.381Z" }, + { url = "https://files.pythonhosted.org/packages/ed/1e/409007f56a2fdce61584fd3acbc2bbc259857d555196cedcadc68c015c82/pillow-12.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1e1757442ed87f4912397c6d35a0db6a7b52592156014706f17658ff58bbf795", size = 7208580, upload-time = "2026-04-01T14:44:08.39Z" }, + { url = "https://files.pythonhosted.org/packages/23/c4/7349421080b12fb35414607b8871e9534546c128a11965fd4a7002ccfbee/pillow-12.2.0-cp313-cp313-win32.whl", hash = "sha256:144748b3af2d1b358d41286056d0003f47cb339b8c43a9ea42f5fea4d8c66b6e", size = 6375896, upload-time = "2026-04-01T14:44:11.197Z" }, + { url = "https://files.pythonhosted.org/packages/3f/82/8a3739a5e470b3c6cbb1d21d315800d8e16bff503d1f16b03a4ec3212786/pillow-12.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:390ede346628ccc626e5730107cde16c42d3836b89662a115a921f28440e6a3b", size = 7081266, upload-time = "2026-04-01T14:44:13.947Z" }, + { url = "https://files.pythonhosted.org/packages/c3/25/f968f618a062574294592f668218f8af564830ccebdd1fa6200f598e65c5/pillow-12.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:8023abc91fba39036dbce14a7d6535632f99c0b857807cbbbf21ecc9f4717f06", size = 2463508, upload-time = "2026-04-01T14:44:16.312Z" }, + { url = "https://files.pythonhosted.org/packages/4d/a4/b342930964e3cb4dce5038ae34b0eab4653334995336cd486c5a8c25a00c/pillow-12.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:042db20a421b9bafecc4b84a8b6e444686bd9d836c7fd24542db3e7df7baad9b", size = 5309927, upload-time = "2026-04-01T14:44:18.89Z" }, + { url = "https://files.pythonhosted.org/packages/9f/de/23198e0a65a9cf06123f5435a5d95cea62a635697f8f03d134d3f3a96151/pillow-12.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:dd025009355c926a84a612fecf58bb315a3f6814b17ead51a8e48d3823d9087f", size = 4698624, upload-time = "2026-04-01T14:44:21.115Z" }, + { url = "https://files.pythonhosted.org/packages/01/a6/1265e977f17d93ea37aa28aa81bad4fa597933879fac2520d24e021c8da3/pillow-12.2.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88ddbc66737e277852913bd1e07c150cc7bb124539f94c4e2df5344494e0a612", size = 6321252, upload-time = "2026-04-01T14:44:23.663Z" }, + { url = "https://files.pythonhosted.org/packages/3c/83/5982eb4a285967baa70340320be9f88e57665a387e3a53a7f0db8231a0cd/pillow-12.2.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d362d1878f00c142b7e1a16e6e5e780f02be8195123f164edf7eddd911eefe7c", size = 8126550, upload-time = "2026-04-01T14:44:26.772Z" }, + { url = "https://files.pythonhosted.org/packages/4e/48/6ffc514adce69f6050d0753b1a18fd920fce8cac87620d5a31231b04bfc5/pillow-12.2.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c727a6d53cb0018aadd8018c2b938376af27914a68a492f59dfcaca650d5eea", size = 6433114, upload-time = "2026-04-01T14:44:29.615Z" }, + { url = "https://files.pythonhosted.org/packages/36/a3/f9a77144231fb8d40ee27107b4463e205fa4677e2ca2548e14da5cf18dce/pillow-12.2.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:efd8c21c98c5cc60653bcb311bef2ce0401642b7ce9d09e03a7da87c878289d4", size = 7115667, upload-time = "2026-04-01T14:44:32.773Z" }, + { url = "https://files.pythonhosted.org/packages/c1/fc/ac4ee3041e7d5a565e1c4fd72a113f03b6394cc72ab7089d27608f8aaccb/pillow-12.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9f08483a632889536b8139663db60f6724bfcb443c96f1b18855860d7d5c0fd4", size = 6538966, upload-time = "2026-04-01T14:44:35.252Z" }, + { url = "https://files.pythonhosted.org/packages/c0/a8/27fb307055087f3668f6d0a8ccb636e7431d56ed0750e07a60547b1e083e/pillow-12.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dac8d77255a37e81a2efcbd1fc05f1c15ee82200e6c240d7e127e25e365c39ea", size = 7238241, upload-time = "2026-04-01T14:44:37.875Z" }, + { url = "https://files.pythonhosted.org/packages/ad/4b/926ab182c07fccae9fcb120043464e1ff1564775ec8864f21a0ebce6ac25/pillow-12.2.0-cp313-cp313t-win32.whl", hash = "sha256:ee3120ae9dff32f121610bb08e4313be87e03efeadfc6c0d18f89127e24d0c24", size = 6379592, upload-time = "2026-04-01T14:44:40.336Z" }, + { url = "https://files.pythonhosted.org/packages/c2/c4/f9e476451a098181b30050cc4c9a3556b64c02cf6497ea421ac047e89e4b/pillow-12.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:325ca0528c6788d2a6c3d40e3568639398137346c3d6e66bb61db96b96511c98", size = 7085542, upload-time = "2026-04-01T14:44:43.251Z" }, + { url = "https://files.pythonhosted.org/packages/00/a4/285f12aeacbe2d6dc36c407dfbbe9e96d4a80b0fb710a337f6d2ad978c75/pillow-12.2.0-cp313-cp313t-win_arm64.whl", hash = "sha256:2e5a76d03a6c6dcef67edabda7a52494afa4035021a79c8558e14af25313d453", size = 2465765, upload-time = "2026-04-01T14:44:45.996Z" }, + { url = "https://files.pythonhosted.org/packages/bf/98/4595daa2365416a86cb0d495248a393dfc84e96d62ad080c8546256cb9c0/pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:3adc9215e8be0448ed6e814966ecf3d9952f0ea40eb14e89a102b87f450660d8", size = 4100848, upload-time = "2026-04-01T14:44:48.48Z" }, + { url = "https://files.pythonhosted.org/packages/0b/79/40184d464cf89f6663e18dfcf7ca21aae2491fff1a16127681bf1fa9b8cf/pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:6a9adfc6d24b10f89588096364cc726174118c62130c817c2837c60cf08a392b", size = 4176515, upload-time = "2026-04-01T14:44:51.353Z" }, + { url = "https://files.pythonhosted.org/packages/b0/63/703f86fd4c422a9cf722833670f4f71418fb116b2853ff7da722ea43f184/pillow-12.2.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:6a6e67ea2e6feda684ed370f9a1c52e7a243631c025ba42149a2cc5934dec295", size = 3640159, upload-time = "2026-04-01T14:44:53.588Z" }, + { url = "https://files.pythonhosted.org/packages/71/e0/fb22f797187d0be2270f83500aab851536101b254bfa1eae10795709d283/pillow-12.2.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2bb4a8d594eacdfc59d9e5ad972aa8afdd48d584ffd5f13a937a664c3e7db0ed", size = 5312185, upload-time = "2026-04-01T14:44:56.039Z" }, + { url = "https://files.pythonhosted.org/packages/ba/8c/1a9e46228571de18f8e28f16fabdfc20212a5d019f3e3303452b3f0a580d/pillow-12.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:80b2da48193b2f33ed0c32c38140f9d3186583ce7d516526d462645fd98660ae", size = 4695386, upload-time = "2026-04-01T14:44:58.663Z" }, + { url = "https://files.pythonhosted.org/packages/70/62/98f6b7f0c88b9addd0e87c217ded307b36be024d4ff8869a812b241d1345/pillow-12.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22db17c68434de69d8ecfc2fe821569195c0c373b25cccb9cbdacf2c6e53c601", size = 6280384, upload-time = "2026-04-01T14:45:01.5Z" }, + { url = "https://files.pythonhosted.org/packages/5e/03/688747d2e91cfbe0e64f316cd2e8005698f76ada3130d0194664174fa5de/pillow-12.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7b14cc0106cd9aecda615dd6903840a058b4700fcb817687d0ee4fc8b6e389be", size = 8091599, upload-time = "2026-04-01T14:45:04.5Z" }, + { url = "https://files.pythonhosted.org/packages/f6/35/577e22b936fcdd66537329b33af0b4ccfefaeabd8aec04b266528cddb33c/pillow-12.2.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cbeb542b2ebc6fcdacabf8aca8c1a97c9b3ad3927d46b8723f9d4f033288a0f", size = 6396021, upload-time = "2026-04-01T14:45:07.117Z" }, + { url = "https://files.pythonhosted.org/packages/11/8d/d2532ad2a603ca2b93ad9f5135732124e57811d0168155852f37fbce2458/pillow-12.2.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4bfd07bc812fbd20395212969e41931001fd59eb55a60658b0e5710872e95286", size = 7083360, upload-time = "2026-04-01T14:45:09.763Z" }, + { url = "https://files.pythonhosted.org/packages/5e/26/d325f9f56c7e039034897e7380e9cc202b1e368bfd04d4cbe6a441f02885/pillow-12.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9aba9a17b623ef750a4d11b742cbafffeb48a869821252b30ee21b5e91392c50", size = 6507628, upload-time = "2026-04-01T14:45:12.378Z" }, + { url = "https://files.pythonhosted.org/packages/5f/f7/769d5632ffb0988f1c5e7660b3e731e30f7f8ec4318e94d0a5d674eb65a4/pillow-12.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:deede7c263feb25dba4e82ea23058a235dcc2fe1f6021025dc71f2b618e26104", size = 7209321, upload-time = "2026-04-01T14:45:15.122Z" }, + { url = "https://files.pythonhosted.org/packages/6a/7a/c253e3c645cd47f1aceea6a8bacdba9991bf45bb7dfe927f7c893e89c93c/pillow-12.2.0-cp314-cp314-win32.whl", hash = "sha256:632ff19b2778e43162304d50da0181ce24ac5bb8180122cbe1bf4673428328c7", size = 6479723, upload-time = "2026-04-01T14:45:17.797Z" }, + { url = "https://files.pythonhosted.org/packages/cd/8b/601e6566b957ca50e28725cb6c355c59c2c8609751efbecd980db44e0349/pillow-12.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:4e6c62e9d237e9b65fac06857d511e90d8461a32adcc1b9065ea0c0fa3a28150", size = 7217400, upload-time = "2026-04-01T14:45:20.529Z" }, + { url = "https://files.pythonhosted.org/packages/d6/94/220e46c73065c3e2951bb91c11a1fb636c8c9ad427ac3ce7d7f3359b9b2f/pillow-12.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:b1c1fbd8a5a1af3412a0810d060a78b5136ec0836c8a4ef9aa11807f2a22f4e1", size = 2554835, upload-time = "2026-04-01T14:45:23.162Z" }, + { url = "https://files.pythonhosted.org/packages/b6/ab/1b426a3974cb0e7da5c29ccff4807871d48110933a57207b5a676cccc155/pillow-12.2.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:57850958fe9c751670e49b2cecf6294acc99e562531f4bd317fa5ddee2068463", size = 5314225, upload-time = "2026-04-01T14:45:25.637Z" }, + { url = "https://files.pythonhosted.org/packages/19/1e/dce46f371be2438eecfee2a1960ee2a243bbe5e961890146d2dee1ff0f12/pillow-12.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d5d38f1411c0ed9f97bcb49b7bd59b6b7c314e0e27420e34d99d844b9ce3b6f3", size = 4698541, upload-time = "2026-04-01T14:45:28.355Z" }, + { url = "https://files.pythonhosted.org/packages/55/c3/7fbecf70adb3a0c33b77a300dc52e424dc22ad8cdc06557a2e49523b703d/pillow-12.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5c0a9f29ca8e79f09de89293f82fc9b0270bb4af1d58bc98f540cc4aedf03166", size = 6322251, upload-time = "2026-04-01T14:45:30.924Z" }, + { url = "https://files.pythonhosted.org/packages/1c/3c/7fbc17cfb7e4fe0ef1642e0abc17fc6c94c9f7a16be41498e12e2ba60408/pillow-12.2.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1610dd6c61621ae1cf811bef44d77e149ce3f7b95afe66a4512f8c59f25d9ebe", size = 8127807, upload-time = "2026-04-01T14:45:33.908Z" }, + { url = "https://files.pythonhosted.org/packages/ff/c3/a8ae14d6defd2e448493ff512fae903b1e9bd40b72efb6ec55ce0048c8ce/pillow-12.2.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a34329707af4f73cf1782a36cd2289c0368880654a2c11f027bcee9052d35dd", size = 6433935, upload-time = "2026-04-01T14:45:36.623Z" }, + { url = "https://files.pythonhosted.org/packages/6e/32/2880fb3a074847ac159d8f902cb43278a61e85f681661e7419e6596803ed/pillow-12.2.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e9c4f5b3c546fa3458a29ab22646c1c6c787ea8f5ef51300e5a60300736905e", size = 7116720, upload-time = "2026-04-01T14:45:39.258Z" }, + { url = "https://files.pythonhosted.org/packages/46/87/495cc9c30e0129501643f24d320076f4cc54f718341df18cc70ec94c44e1/pillow-12.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fb043ee2f06b41473269765c2feae53fc2e2fbf96e5e22ca94fb5ad677856f06", size = 6540498, upload-time = "2026-04-01T14:45:41.879Z" }, + { url = "https://files.pythonhosted.org/packages/18/53/773f5edca692009d883a72211b60fdaf8871cbef075eaa9d577f0a2f989e/pillow-12.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f278f034eb75b4e8a13a54a876cc4a5ab39173d2cdd93a638e1b467fc545ac43", size = 7239413, upload-time = "2026-04-01T14:45:44.705Z" }, + { url = "https://files.pythonhosted.org/packages/c9/e4/4b64a97d71b2a83158134abbb2f5bd3f8a2ea691361282f010998f339ec7/pillow-12.2.0-cp314-cp314t-win32.whl", hash = "sha256:6bb77b2dcb06b20f9f4b4a8454caa581cd4dd0643a08bacf821216a16d9c8354", size = 6482084, upload-time = "2026-04-01T14:45:47.568Z" }, + { url = "https://files.pythonhosted.org/packages/ba/13/306d275efd3a3453f72114b7431c877d10b1154014c1ebbedd067770d629/pillow-12.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6562ace0d3fb5f20ed7290f1f929cae41b25ae29528f2af1722966a0a02e2aa1", size = 7225152, upload-time = "2026-04-01T14:45:50.032Z" }, + { url = "https://files.pythonhosted.org/packages/ff/6e/cf826fae916b8658848d7b9f38d88da6396895c676e8086fc0988073aaf8/pillow-12.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:aa88ccfe4e32d362816319ed727a004423aab09c5cea43c01a4b435643fa34eb", size = 2556579, upload-time = "2026-04-01T14:45:52.529Z" }, + { url = "https://files.pythonhosted.org/packages/4e/b7/2437044fb910f499610356d1352e3423753c98e34f915252aafecc64889f/pillow-12.2.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0538bd5e05efec03ae613fd89c4ce0368ecd2ba239cc25b9f9be7ed426b0af1f", size = 5273969, upload-time = "2026-04-01T14:45:55.538Z" }, + { url = "https://files.pythonhosted.org/packages/f6/f4/8316e31de11b780f4ac08ef3654a75555e624a98db1056ecb2122d008d5a/pillow-12.2.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:394167b21da716608eac917c60aa9b969421b5dcbbe02ae7f013e7b85811c69d", size = 4659674, upload-time = "2026-04-01T14:45:58.093Z" }, + { url = "https://files.pythonhosted.org/packages/d4/37/664fca7201f8bb2aa1d20e2c3d5564a62e6ae5111741966c8319ca802361/pillow-12.2.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5d04bfa02cc2d23b497d1e90a0f927070043f6cbf303e738300532379a4b4e0f", size = 5288479, upload-time = "2026-04-01T14:46:01.141Z" }, + { url = "https://files.pythonhosted.org/packages/49/62/5b0ed78fce87346be7a5cfcfaaad91f6a1f98c26f86bdbafa2066c647ef6/pillow-12.2.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0c838a5125cee37e68edec915651521191cef1e6aa336b855f495766e77a366e", size = 7032230, upload-time = "2026-04-01T14:46:03.874Z" }, + { url = "https://files.pythonhosted.org/packages/c3/28/ec0fc38107fc32536908034e990c47914c57cd7c5a3ece4d8d8f7ffd7e27/pillow-12.2.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a6c9fa44005fa37a91ebfc95d081e8079757d2e904b27103f4f5fa6f0bf78c0", size = 5355404, upload-time = "2026-04-01T14:46:06.33Z" }, + { url = "https://files.pythonhosted.org/packages/5e/8b/51b0eddcfa2180d60e41f06bd6d0a62202b20b59c68f5a132e615b75aecf/pillow-12.2.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:25373b66e0dd5905ed63fa3cae13c82fbddf3079f2c8bf15c6fb6a35586324c1", size = 6002215, upload-time = "2026-04-01T14:46:08.83Z" }, + { url = "https://files.pythonhosted.org/packages/bc/60/5382c03e1970de634027cee8e1b7d39776b778b81812aaf45b694dfe9e28/pillow-12.2.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:bfa9c230d2fe991bed5318a5f119bd6780cda2915cca595393649fc118ab895e", size = 7080946, upload-time = "2026-04-01T14:46:11.734Z" }, +] + +[[package]] +name = "plotly" +version = "6.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "narwhals" }, + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3a/7f/0f100df1172aadf88a929a9dbb902656b0880ba4b960fe5224867159d8f4/plotly-6.7.0.tar.gz", hash = "sha256:45eea0ff27e2a23ccd62776f77eb43aa1ca03df4192b76036e380bb479b892c6", size = 6911286, upload-time = "2026-04-09T20:36:45.738Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/ad/cba91b3bcf04073e4d1655a5c1710ef3f457f56f7d1b79dcc3d72f4dd912/plotly-6.7.0-py3-none-any.whl", hash = "sha256:ac8aca1c25c663a59b5b9140a549264a5badde2e057d79b8c772ae2920e32ff0", size = 9898444, upload-time = "2026-04-09T20:36:39.812Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "polars" +version = "1.40.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "polars-runtime-32" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/8c/bc9bc948058348ed43117cecc3007cd608f395915dae8a00974579a5dab1/polars-1.40.1.tar.gz", hash = "sha256:ab2694134b137596b5a59bfd7b4c54ebbc9b59f9403127f18e32d363777552e8", size = 733574, upload-time = "2026-04-22T19:15:55.507Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/91/74fc60d94488685a92ac9d49d7ec55f3e91fe9b77942a6235a5fa7f249c3/polars-1.40.1-py3-none-any.whl", hash = "sha256:c0f861219d1319cdea45c4ce4d30355a47176b8f98dcedf95ea8269f131b8abd", size = 828723, upload-time = "2026-04-22T19:14:25.452Z" }, +] + +[[package]] +name = "polars-runtime-32" +version = "1.40.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/ba/26d40f039be9f552b5fd7365a621bdfc0f8e912ef77094ae4693491b0bae/polars_runtime_32-1.40.1.tar.gz", hash = "sha256:37f3065615d1bf90d03b5326222df4c5c1f8a5d33e50470aa588e3465e6eb814", size = 2935843, upload-time = "2026-04-22T19:15:57.26Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/46/22c8af5eed68ac2eeb556e0fa3ca8a7b798e984ceff4450888f3b5ac61fd/polars_runtime_32-1.40.1-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:b748ef652270cc49e9e69f99a035e0eb4d5f856d42bcd6ac4d9d80a40142aa1e", size = 52098755, upload-time = "2026-04-22T19:14:28.555Z" }, + { url = "https://files.pythonhosted.org/packages/c6/3e/48599a38009ca60ff82a6f38c8a621ce3c0286aa7397c7d79e741bd9060e/polars_runtime_32-1.40.1-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:d249b3743e05986060cec0a7aaa542d020df6c6b876e556023a310efd581f9be", size = 46367542, upload-time = "2026-04-22T19:14:32.433Z" }, + { url = "https://files.pythonhosted.org/packages/43/e9/384bc069367a1a36ee31c13782c178dbd039b2b873b772d4a0fc23a2373d/polars_runtime_32-1.40.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5987b30e7aa1059d069498496e8dda35afd592b0ac3d46ed87e3ff8df1ad652c", size = 50252104, upload-time = "2026-04-22T19:14:35.945Z" }, + { url = "https://files.pythonhosted.org/packages/15/ef/7d57ceb0651af74194e97ed6583e148d352f03d696090221b8059cdfc90b/polars_runtime_32-1.40.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d7f42a8b3f16fc66002cc0f6516f7dd7653396886ae0ed362ab95c0b3408b59", size = 56250788, upload-time = "2026-04-22T19:14:39.743Z" }, + { url = "https://files.pythonhosted.org/packages/10/0f/e4b3ffc748827a14a474ec9c42e45c066050e440fec57e914091d9adda75/polars_runtime_32-1.40.1-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e5f7becc237a7ec9d9a10878dc8e54b73bbf4e2d94a2991c37d7a0b38590d8f9", size = 50432590, upload-time = "2026-04-22T19:14:43.388Z" }, + { url = "https://files.pythonhosted.org/packages/d9/0b/b8d95fbed869fa4caabe9c400e4210374913b376e925e96fdcfa9be6416b/polars_runtime_32-1.40.1-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:992d14cf191dde043d36fbdbc98a65e43fbc7e9a5024cecd45f838ac4988c1ee", size = 54155564, upload-time = "2026-04-22T19:14:47.239Z" }, + { url = "https://files.pythonhosted.org/packages/06/d9/d091d8fb5cbed5e9536adfed955c4c89987a4cc3b8e73ae4532402b91c74/polars_runtime_32-1.40.1-cp310-abi3-win_amd64.whl", hash = "sha256:f78bb2abd00101cbb23cc0cb068f7e36e081057a15d2ec2dde3dda280709f030", size = 51829755, upload-time = "2026-04-22T19:14:50.85Z" }, + { url = "https://files.pythonhosted.org/packages/65/ad/b33c3022a394f3eb55c3310597cec615412a8a33880055eee191d154a628/polars_runtime_32-1.40.1-cp310-abi3-win_arm64.whl", hash = "sha256:b5cbfaf6b085b420b4bfcbe24e8f665076d1cccfdb80c0484c02a023ce205537", size = 45822104, upload-time = "2026-04-22T19:14:54.192Z" }, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.52" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, +] + +[[package]] +name = "psutil" +version = "7.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/c6/d1ddf4abb55e93cebc4f2ed8b5d6dbad109ecb8d63748dd2b20ab5e57ebe/psutil-7.2.2.tar.gz", hash = "sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372", size = 493740, upload-time = "2026-01-28T18:14:54.428Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/08/510cbdb69c25a96f4ae523f733cdc963ae654904e8db864c07585ef99875/psutil-7.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2edccc433cbfa046b980b0df0171cd25bcaeb3a68fe9022db0979e7aa74a826b", size = 130595, upload-time = "2026-01-28T18:14:57.293Z" }, + { url = "https://files.pythonhosted.org/packages/d6/f5/97baea3fe7a5a9af7436301f85490905379b1c6f2dd51fe3ecf24b4c5fbf/psutil-7.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e78c8603dcd9a04c7364f1a3e670cea95d51ee865e4efb3556a3a63adef958ea", size = 131082, upload-time = "2026-01-28T18:14:59.732Z" }, + { url = "https://files.pythonhosted.org/packages/37/d6/246513fbf9fa174af531f28412297dd05241d97a75911ac8febefa1a53c6/psutil-7.2.2-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a571f2330c966c62aeda00dd24620425d4b0cc86881c89861fbc04549e5dc63", size = 181476, upload-time = "2026-01-28T18:15:01.884Z" }, + { url = "https://files.pythonhosted.org/packages/b8/b5/9182c9af3836cca61696dabe4fd1304e17bc56cb62f17439e1154f225dd3/psutil-7.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:917e891983ca3c1887b4ef36447b1e0873e70c933afc831c6b6da078ba474312", size = 184062, upload-time = "2026-01-28T18:15:04.436Z" }, + { url = "https://files.pythonhosted.org/packages/16/ba/0756dca669f5a9300d0cbcbfae9a4c30e446dfc7440ffe43ded5724bfd93/psutil-7.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:ab486563df44c17f5173621c7b198955bd6b613fb87c71c161f827d3fb149a9b", size = 139893, upload-time = "2026-01-28T18:15:06.378Z" }, + { url = "https://files.pythonhosted.org/packages/1c/61/8fa0e26f33623b49949346de05ec1ddaad02ed8ba64af45f40a147dbfa97/psutil-7.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:ae0aefdd8796a7737eccea863f80f81e468a1e4cf14d926bd9b6f5f2d5f90ca9", size = 135589, upload-time = "2026-01-28T18:15:08.03Z" }, + { url = "https://files.pythonhosted.org/packages/81/69/ef179ab5ca24f32acc1dac0c247fd6a13b501fd5534dbae0e05a1c48b66d/psutil-7.2.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:eed63d3b4d62449571547b60578c5b2c4bcccc5387148db46e0c2313dad0ee00", size = 130664, upload-time = "2026-01-28T18:15:09.469Z" }, + { url = "https://files.pythonhosted.org/packages/7b/64/665248b557a236d3fa9efc378d60d95ef56dd0a490c2cd37dafc7660d4a9/psutil-7.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7b6d09433a10592ce39b13d7be5a54fbac1d1228ed29abc880fb23df7cb694c9", size = 131087, upload-time = "2026-01-28T18:15:11.724Z" }, + { url = "https://files.pythonhosted.org/packages/d5/2e/e6782744700d6759ebce3043dcfa661fb61e2fb752b91cdeae9af12c2178/psutil-7.2.2-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fa4ecf83bcdf6e6c8f4449aff98eefb5d0604bf88cb883d7da3d8d2d909546a", size = 182383, upload-time = "2026-01-28T18:15:13.445Z" }, + { url = "https://files.pythonhosted.org/packages/57/49/0a41cefd10cb7505cdc04dab3eacf24c0c2cb158a998b8c7b1d27ee2c1f5/psutil-7.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e452c464a02e7dc7822a05d25db4cde564444a67e58539a00f929c51eddda0cf", size = 185210, upload-time = "2026-01-28T18:15:16.002Z" }, + { url = "https://files.pythonhosted.org/packages/dd/2c/ff9bfb544f283ba5f83ba725a3c5fec6d6b10b8f27ac1dc641c473dc390d/psutil-7.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c7663d4e37f13e884d13994247449e9f8f574bc4655d509c3b95e9ec9e2b9dc1", size = 141228, upload-time = "2026-01-28T18:15:18.385Z" }, + { url = "https://files.pythonhosted.org/packages/f2/fc/f8d9c31db14fcec13748d373e668bc3bed94d9077dbc17fb0eebc073233c/psutil-7.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:11fe5a4f613759764e79c65cf11ebdf26e33d6dd34336f8a337aa2996d71c841", size = 136284, upload-time = "2026-01-28T18:15:19.912Z" }, + { url = "https://files.pythonhosted.org/packages/e7/36/5ee6e05c9bd427237b11b3937ad82bb8ad2752d72c6969314590dd0c2f6e/psutil-7.2.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486", size = 129090, upload-time = "2026-01-28T18:15:22.168Z" }, + { url = "https://files.pythonhosted.org/packages/80/c4/f5af4c1ca8c1eeb2e92ccca14ce8effdeec651d5ab6053c589b074eda6e1/psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979", size = 129859, upload-time = "2026-01-28T18:15:23.795Z" }, + { url = "https://files.pythonhosted.org/packages/b5/70/5d8df3b09e25bce090399cf48e452d25c935ab72dad19406c77f4e828045/psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9", size = 155560, upload-time = "2026-01-28T18:15:25.976Z" }, + { url = "https://files.pythonhosted.org/packages/63/65/37648c0c158dc222aba51c089eb3bdfa238e621674dc42d48706e639204f/psutil-7.2.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e", size = 156997, upload-time = "2026-01-28T18:15:27.794Z" }, + { url = "https://files.pythonhosted.org/packages/8e/13/125093eadae863ce03c6ffdbae9929430d116a246ef69866dad94da3bfbc/psutil-7.2.2-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8", size = 148972, upload-time = "2026-01-28T18:15:29.342Z" }, + { url = "https://files.pythonhosted.org/packages/04/78/0acd37ca84ce3ddffaa92ef0f571e073faa6d8ff1f0559ab1272188ea2be/psutil-7.2.2-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc", size = 148266, upload-time = "2026-01-28T18:15:31.597Z" }, + { url = "https://files.pythonhosted.org/packages/b4/90/e2159492b5426be0c1fef7acba807a03511f97c5f86b3caeda6ad92351a7/psutil-7.2.2-cp37-abi3-win_amd64.whl", hash = "sha256:eb7e81434c8d223ec4a219b5fc1c47d0417b12be7ea866e24fb5ad6e84b3d988", size = 137737, upload-time = "2026-01-28T18:15:33.849Z" }, + { url = "https://files.pythonhosted.org/packages/8c/c7/7bb2e321574b10df20cbde462a94e2b71d05f9bbda251ef27d104668306a/psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee", size = 134617, upload-time = "2026-01-28T18:15:36.514Z" }, +] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, +] + +[[package]] +name = "pure-eval" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, +] + +[[package]] +name = "pyarrow" +version = "24.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/91/13/13e1069b351bdc3881266e11147ffccf687505dbb0ea74036237f5d454a5/pyarrow-24.0.0.tar.gz", hash = "sha256:85fe721a14dd823aca09127acbb06c3ca723efbd436c004f16bca601b04dcc83", size = 1180261, upload-time = "2026-04-21T10:51:25.837Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/c9/a47ab7ece0d86cbe6678418a0fbd1ac4bb493b9184a3891dfa0e7f287ae0/pyarrow-24.0.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:b0e131f880cda8d04e076cee175a46fc0e8bc8b65c99c6c09dff6669335fde74", size = 35068898, upload-time = "2026-04-21T10:46:36.599Z" }, + { url = "https://files.pythonhosted.org/packages/d1/bc/8db86617a9a58008acf8913d6fed68ea2a46acb6de928db28d724c891a68/pyarrow-24.0.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:1b2fe7f9a5566401a0ef2571f197eb92358925c1f0c8dba305d6e43ea0871bb3", size = 36679915, upload-time = "2026-04-21T10:46:42.602Z" }, + { url = "https://files.pythonhosted.org/packages/eb/8e/fb178720400ef69db251eb4a9c3ccf4af269bc1feb5055529b8fc87170d1/pyarrow-24.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:0b3537c00fb8d384f15ac1e79b6eb6db04a16514c8c1d22e59a9b95c8ba42868", size = 45697931, upload-time = "2026-04-21T10:46:48.403Z" }, + { url = "https://files.pythonhosted.org/packages/f3/27/99c42abe8e21b44f4917f62631f3aa31404882a2c41d8a4cd5c110e13d52/pyarrow-24.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:14e31a3c9e35f1ab6356c6378f6f72830e6d2d5f1791df3774a7b097d18a6a1e", size = 48837449, upload-time = "2026-04-21T10:46:55.329Z" }, + { url = "https://files.pythonhosted.org/packages/36/b6/333749e2666e9032891125bf9c691146e92901bece62030ac1430e2e7c88/pyarrow-24.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b7d9a514e73bc42711e6a35aaccf3587c520024fe0a25d830a1a8a27c15f4f57", size = 49395949, upload-time = "2026-04-21T10:47:01.869Z" }, + { url = "https://files.pythonhosted.org/packages/17/25/c5201706a2dd374e8ba6ee3fd7a8c89fb7ffc16eed5217a91fd2bd7f7626/pyarrow-24.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b196eb3f931862af3fa84c2a253514d859c08e0d8fe020e07be12e75a5a9780c", size = 51912986, upload-time = "2026-04-21T10:47:09.872Z" }, + { url = "https://files.pythonhosted.org/packages/f8/d2/4d1bbba65320b21a49678d6fbdc6ff7c649251359fdcfc03568c4136231d/pyarrow-24.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:35405aecb474e683fb36af650618fd5340ee5471fc65a21b36076a18bbc6c981", size = 27255371, upload-time = "2026-04-21T10:47:15.943Z" }, + { url = "https://files.pythonhosted.org/packages/b4/a9/9686d9f07837f91f775e8932659192e02c74f9d8920524b480b85212cc68/pyarrow-24.0.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:6233c9ed9ab9d1db47de57d9753256d9dcffbf42db341576099f0fd9f6bf4810", size = 34981559, upload-time = "2026-04-21T10:47:22.17Z" }, + { url = "https://files.pythonhosted.org/packages/80/b6/0ddf0e9b6ead3474ab087ae598c76b031fc45532bf6a63f3a553440fb258/pyarrow-24.0.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:f7616236ec1bc2b15bfdec22a71ab38851c86f8f05ff64f379e1278cf20c634a", size = 36663654, upload-time = "2026-04-21T10:47:28.315Z" }, + { url = "https://files.pythonhosted.org/packages/7c/3b/926382efe8ce27ba729071d3566ade6dfb86bdf112f366000196b2f5780a/pyarrow-24.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:1617043b99bd33e5318ae18eb2919af09c71322ef1ca46566cdafc6e6712fb66", size = 45679394, upload-time = "2026-04-21T10:47:34.821Z" }, + { url = "https://files.pythonhosted.org/packages/b3/7a/829f7d9dfd37c207206081d6dad474d81dde29952401f07f2ba507814818/pyarrow-24.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6165461f55ef6314f026de6638d661188e3455d3ec49834556a0ebbdbace18bb", size = 48863122, upload-time = "2026-04-21T10:47:42.056Z" }, + { url = "https://files.pythonhosted.org/packages/5f/e8/f88ce625fe8babaae64e8db2d417c7653adb3019b08aae85c5ed787dc816/pyarrow-24.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3b13dedfe76a0ad2d1d859b0811b53827a4e9d93a0bcb05cf59333ab4980cc7e", size = 49376032, upload-time = "2026-04-21T10:47:48.967Z" }, + { url = "https://files.pythonhosted.org/packages/36/7a/82c363caa145fff88fb475da50d3bf52bb024f61917be5424c3392eaf878/pyarrow-24.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:25ea65d868eb04015cd18e6df2fbe98f07e5bda2abefabcb88fce39a947716f6", size = 51929490, upload-time = "2026-04-21T10:47:55.981Z" }, + { url = "https://files.pythonhosted.org/packages/66/1c/e3e72c8014ad2743ca64a701652c733cc5cbcee15c0463a32a8c55518d9e/pyarrow-24.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:295f0a7f2e242dabd513737cf076007dc5b2d59237e3eca37b05c0c6446f3826", size = 27355660, upload-time = "2026-04-21T10:48:01.718Z" }, + { url = "https://files.pythonhosted.org/packages/6f/d3/a1abf004482026ddc17f4503db227787fa3cfe41ec5091ff20e4fea55e57/pyarrow-24.0.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:02b001b3ed4723caa44f6cd1af2d5c86aa2cf9971dacc2ffa55b21237713dfba", size = 34976759, upload-time = "2026-04-21T10:48:07.258Z" }, + { url = "https://files.pythonhosted.org/packages/4f/4a/34f0a36d28a2dd32225301b79daad44e243dc1a2bb77d43b60749be255c4/pyarrow-24.0.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:04920d6a71aabd08a0417709efce97d45ea8e6fb733d9ca9ecffb13c67839f68", size = 36658471, upload-time = "2026-04-21T10:48:13.347Z" }, + { url = "https://files.pythonhosted.org/packages/1f/78/543b94712ae8bb1a6023bcc1acf1a740fbff8286747c289cd9468fced2a5/pyarrow-24.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:a964266397740257f16f7bb2e4f08a0c81454004beab8ff59dd531b73610e9f2", size = 45675981, upload-time = "2026-04-21T10:48:20.201Z" }, + { url = "https://files.pythonhosted.org/packages/84/9f/8fb7c222b100d314137fa40ec050de56cd8c6d957d1cfff685ce72f15b17/pyarrow-24.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:6f066b179d68c413374294bc1735f68475457c933258df594443bb9d88ddc2a0", size = 48859172, upload-time = "2026-04-21T10:48:27.541Z" }, + { url = "https://files.pythonhosted.org/packages/a7/d3/1ea72538e6c8b3b475ed78d1049a2c518e655761ea50fe1171fc855fcab7/pyarrow-24.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1183baeb14c5f587b1ec52831e665718ce632caab84b7cd6b85fd44f96114495", size = 49385733, upload-time = "2026-04-21T10:48:34.7Z" }, + { url = "https://files.pythonhosted.org/packages/c3/be/c3d8b06a1ba35f2260f8e1f771abbee7d5e345c0937aab90675706b1690a/pyarrow-24.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:806f24b4085453c197a5078218d1ee08783ebbba271badd153d1ae22a3ee804f", size = 51934335, upload-time = "2026-04-21T10:48:42.099Z" }, + { url = "https://files.pythonhosted.org/packages/9c/62/89e07a1e7329d2cde3e3c6994ba0839a24977a2beda8be6005ea3d860b99/pyarrow-24.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:e4505fc6583f7b05ab854934896bcac8253b04ac1171a77dfb73efef92076d91", size = 27271748, upload-time = "2026-04-21T10:49:42.532Z" }, + { url = "https://files.pythonhosted.org/packages/17/1a/cff3a59f80b5b1658549d46611b67163f65e0664431c076ad728bf9d5af4/pyarrow-24.0.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:1a4e45017efbf115032e4475ee876d525e0e36c742214fbe405332480ecd6275", size = 35238554, upload-time = "2026-04-21T10:48:48.526Z" }, + { url = "https://files.pythonhosted.org/packages/a8/99/cce0f42a327bfef2c420fb6078a3eb834826e5d6697bf3009fe11d2ad051/pyarrow-24.0.0-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:7986f1fa71cee060ad00758bcc79d3a93bab8559bf978fab9e53472a2e25a17b", size = 36782301, upload-time = "2026-04-21T10:48:55.181Z" }, + { url = "https://files.pythonhosted.org/packages/2a/66/8e560d5ff6793ca29aca213c53eec0dd482dd46cb93b2819e5aab52e4252/pyarrow-24.0.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:d3e0b61e8efb24ed38898e5cdc5fffa9124be480008d401a1f8071500494ae42", size = 45721929, upload-time = "2026-04-21T10:49:03.676Z" }, + { url = "https://files.pythonhosted.org/packages/27/0c/a26e25505d030716e078d9f16eb74973cbf0b33b672884e9f9da1c83b871/pyarrow-24.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:55a3bc1e3df3b5567b7d27ef551b2283f0c68a5e86f1cd56abc569da4f31335b", size = 48825365, upload-time = "2026-04-21T10:49:11.714Z" }, + { url = "https://files.pythonhosted.org/packages/5f/eb/771f9ecb0c65e73fe9dccdd1717901b9594f08c4515d000c7c62df573811/pyarrow-24.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:641f795b361874ac9da5294f8f443dfdbee355cf2bd9e3b8d97aaac2306b9b37", size = 49451819, upload-time = "2026-04-21T10:49:21.474Z" }, + { url = "https://files.pythonhosted.org/packages/48/da/61ae89a88732f5a785646f3ec6125dbb640fa98a540eb2b9889caa561403/pyarrow-24.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8adc8e6ce5fccf5dc707046ae4914fd537def529709cc0d285d37a7f9cd442ca", size = 51909252, upload-time = "2026-04-21T10:49:31.164Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1a/8dd5cafab7b66573fa91c03d06d213356ad4edd71813aa75e08ce2b3a844/pyarrow-24.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:9b18371ad2f44044b81a8d23bc2d8a9b6a6226dca775e8e16cfee640473d6c5d", size = 27388127, upload-time = "2026-04-21T10:49:37.334Z" }, + { url = "https://files.pythonhosted.org/packages/ad/80/d022a34ff05d2cbedd8ccf841fc1f532ecfa9eb5ed1711b56d0e0ea71fc9/pyarrow-24.0.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:1cc9057f0319e26333b357e17f3c2c022f1a83739b48a88b25bfd5fa2dc18838", size = 35007997, upload-time = "2026-04-21T10:49:48.796Z" }, + { url = "https://files.pythonhosted.org/packages/1a/ff/f01485fda6f4e5d441afb8dd5e7681e4db18826c1e271852f5d3957d6a80/pyarrow-24.0.0-cp314-cp314-macosx_12_0_x86_64.whl", hash = "sha256:e6f1278ee4785b6db21229374a1c9e54ec7c549de5d1efc9630b6207de7e170b", size = 36678720, upload-time = "2026-04-21T10:49:55.858Z" }, + { url = "https://files.pythonhosted.org/packages/9e/c2/2d2d5fea814237923f71b36495211f20b43a1576f9a4d6da7e751a64ec6f/pyarrow-24.0.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:adbbedc55506cbdabb830890444fb856bfb0060c46c6f8026c6c2f2cf86ae795", size = 45741852, upload-time = "2026-04-21T10:50:04.624Z" }, + { url = "https://files.pythonhosted.org/packages/8e/3a/28ba9c1c1ebdbb5f1b94dfebb46f207e52e6a554b7fe4132540fde29a3a0/pyarrow-24.0.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:ae8a1145af31d903fa9bb166824d7abe9b4681a000b0159c9fb99c11bc11ad26", size = 48889852, upload-time = "2026-04-21T10:50:12.293Z" }, + { url = "https://files.pythonhosted.org/packages/df/51/4a389acfd31dca009f8fb82d7f510bb4130f2b3a8e18cf00194d0687d8ac/pyarrow-24.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d7027eba1df3b2069e2e8d80f644fa0918b68c46432af3d088ddd390d063ecde", size = 49445207, upload-time = "2026-04-21T10:50:20.677Z" }, + { url = "https://files.pythonhosted.org/packages/19/4b/0bab2b23d2ae901b1b9a03c0efd4b2d070256f8ce3fc43f6e58c167b2081/pyarrow-24.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e56a1ffe9bf7b727432b89104cc0849c21582949dd7bdcb34f17b2001a351a76", size = 51954117, upload-time = "2026-04-21T10:50:29.14Z" }, + { url = "https://files.pythonhosted.org/packages/29/88/f4e9145da0417b3d2c12035a8492b35ff4a3dbc653e614fcfb51d9dedb38/pyarrow-24.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:38be1808cdd068605b787e6ca9119b27eb275a0234e50212c3492331680c3b1e", size = 28001155, upload-time = "2026-04-21T10:51:22.337Z" }, + { url = "https://files.pythonhosted.org/packages/79/4f/46a49a63f43526da895b1a45bbb51d5baf8e4d77159f8528fc3e5490007f/pyarrow-24.0.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:418e48ce50a45a6a6c73c454677203a9c75c966cb1e92ca3370959185f197a05", size = 35250387, upload-time = "2026-04-21T10:50:35.552Z" }, + { url = "https://files.pythonhosted.org/packages/a0/da/d5e0cd5ef00796922404806d5f00325cdadc3441ce2c13fe7115f2df9a64/pyarrow-24.0.0-cp314-cp314t-macosx_12_0_x86_64.whl", hash = "sha256:2f16197705a230a78270cdd4ea8a1d57e86b2fdcbc34a1f6aebc72e65c986f9a", size = 36797102, upload-time = "2026-04-21T10:50:42.417Z" }, + { url = "https://files.pythonhosted.org/packages/34/c7/5904145b0a593a05236c882933d439b5720f0a145381179063722fbfc123/pyarrow-24.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:fb24ac194bfc5e86839d7dcd52092ee31e5fe6733fe11f5e3b06ef0812b20072", size = 45745118, upload-time = "2026-04-21T10:50:49.324Z" }, + { url = "https://files.pythonhosted.org/packages/13/d3/cca42fe166d1c6e4d5b80e530b7949104d10e17508a90ae202dac205ce2a/pyarrow-24.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:9700ebd9a51f5895ce75ff4ac4b3c47a7d4b42bc618be8e713e5d56bacf5f931", size = 48844765, upload-time = "2026-04-21T10:50:55.579Z" }, + { url = "https://files.pythonhosted.org/packages/b0/49/942c3b79878ba928324d1e17c274ed84581db8c0a749b24bcf4cbdf15bd3/pyarrow-24.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d8ddd2768da81d3ee08cfea9b597f4abb4e8e1dc8ae7e204b608d23a0d3ab699", size = 49471890, upload-time = "2026-04-21T10:51:02.439Z" }, + { url = "https://files.pythonhosted.org/packages/76/97/ff71431000a75d84135a1ace5ca4ba11726a231a8007bbb320a4c54075d5/pyarrow-24.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:61a3d7eaa97a14768b542f3d284dc6400dd2470d9f080708b13cd46b6ae18136", size = 51932250, upload-time = "2026-04-21T10:51:10.576Z" }, + { url = "https://files.pythonhosted.org/packages/51/be/6f79d55816d5c22557cf27533543d5d70dfe692adfbee4b99f2760674f38/pyarrow-24.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:c91d00057f23b8d353039520dc3a6c09d8608164c692e9f59a175a42b2ae0c19", size = 28131282, upload-time = "2026-04-21T10:51:16.815Z" }, +] + +[[package]] +name = "pydantic" +version = "2.13.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/18/a5/b60d21ac674192f8ab0ba4e9fd860690f9b4a6e51ca5df118733b487d8d6/pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6", size = 844775, upload-time = "2026-05-06T13:43:05.343Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl", hash = "sha256:45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba", size = 472262, upload-time = "2026-05-06T13:43:02.641Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.46.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", size = 471464, upload-time = "2026-05-06T13:37:06.98Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/fa/6d7708d2cfc1a832acb6aeb0cd16e801902df8a0f583bb3b4b527fde022e/pydantic_core-2.46.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0e96592440881c74a213e5ad528e2b24d3d4f940de2766bed9010ab1d9e51594", size = 2111872, upload-time = "2026-05-06T13:40:27.596Z" }, + { url = "https://files.pythonhosted.org/packages/ae/6f/aa064a3e74b5745afbdf250594f38e7ead05e2d651bcb35994b9417a0d4d/pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0d65b8c354be7fb5f720c3caa8bc940bc2d20ce749c8e06135f07f8ed95dd7c", size = 1948255, upload-time = "2026-05-06T13:39:12.574Z" }, + { url = "https://files.pythonhosted.org/packages/43/3a/41114a9f7569b84b4d84e7a018c57c56347dac30c0d4a872946ec4e36c46/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bfb192b3f4b9e8a89b6277b6ce787564f62cfd272055f6e685726b111dc7826", size = 1972827, upload-time = "2026-05-06T13:38:19.841Z" }, + { url = "https://files.pythonhosted.org/packages/ef/25/1ab42e8048fe551934d9884e8d64daa7e990ad386f310a15981aeb6a5b08/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9037063db01f09b09e237c282b6792bd4da634b5402c4e7f0c61effed7701a04", size = 2041051, upload-time = "2026-05-06T13:38:10.447Z" }, + { url = "https://files.pythonhosted.org/packages/94/c2/1a934597ddf08da410385b3b7aae91956a5a76c635effef456074fad7e88/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc010ab034c8c7452522748bf937df58020d256ccae0874463d1f4d01758af8e", size = 2221314, upload-time = "2026-05-06T13:40:13.089Z" }, + { url = "https://files.pythonhosted.org/packages/02/6d/9e8ad178c9c4df27ad3c8f25d1fe2a7ab0d2ba0559fad4aee5d3d1f16771/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c5dac79fa1614d1e06ca695109c6105923bd9c7d1d6c918d4e637b7e6b32fd3", size = 2285146, upload-time = "2026-05-06T13:38:59.224Z" }, + { url = "https://files.pythonhosted.org/packages/80/50/540cd3aeefc041beb111125c4bff779831a2111fc6b15a9138cda277d32c/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9fa868638bf362d3d138ea55829cefb3d5f4b0d7f142234382a15e2485dbec4", size = 2089685, upload-time = "2026-05-06T13:38:17.762Z" }, + { url = "https://files.pythonhosted.org/packages/6b/a4/b440ad35f05f6a38f89fa0f149accb3f0e02be94ca5e15f3c449a61b4bc9/pydantic_core-2.46.4-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:17299feefe090f2caa5b8e37222bb5f663e4935a8bfa6931d4102e5df1a9f398", size = 2115420, upload-time = "2026-05-06T13:37:58.195Z" }, + { url = "https://files.pythonhosted.org/packages/99/61/de4f55db8dfd57bfdfa9a12ec90fe1b57c4f41062f7ca86f08586b3e0ac0/pydantic_core-2.46.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4c63ebc82684aa89d9a3bcbd13d515b3be44250dc68dd3bd81526c1cb31286c3", size = 2165122, upload-time = "2026-05-06T13:37:01.167Z" }, + { url = "https://files.pythonhosted.org/packages/f7/52/7c529d7bdb2d1068bd52f51fe32572c8301f9a4febf1948f10639f1436f5/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:aaa2a54443eff1950ba5ddc6b6ccda0d9c84a364276a62f969bdf2a390650848", size = 2182573, upload-time = "2026-05-06T13:38:45.04Z" }, + { url = "https://files.pythonhosted.org/packages/37/b3/7c40325848ba78247f2812dcf9c7274e38cd801820ca6dd9fe63bcfb0eb4/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:18e5ceec2ab67e6d5f1a9085e5a24c9c4e2ac4545730bfe668680bca05e555f3", size = 2317139, upload-time = "2026-05-06T13:37:15.539Z" }, + { url = "https://files.pythonhosted.org/packages/d9/37/f913f81a657c865b75da6c0dbed79876073c2a43b5bd9edbe8da785e4d49/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a0f62d0a58f4e7da165457e995725421e0064f2255d8eccebc49f41bbc23b109", size = 2360433, upload-time = "2026-05-06T13:37:30.099Z" }, + { url = "https://files.pythonhosted.org/packages/c4/67/6acaa1be2567f9256b056d8477158cac7240813956ce86e49deae8e173b4/pydantic_core-2.46.4-cp311-cp311-win32.whl", hash = "sha256:041bde0a48fd37cf71cab1c9d56d3e8625a3793fef1f7dd232b3ff37e978ecda", size = 1985513, upload-time = "2026-05-06T13:38:15.669Z" }, + { url = "https://files.pythonhosted.org/packages/aa/e6/c505f83dfeda9a2e5c995cfd872949e4d05e12f7feb3dca72f633daefa94/pydantic_core-2.46.4-cp311-cp311-win_amd64.whl", hash = "sha256:6f2eeda33a839975441c86a4119e1383c50b47faf0cbb5176985565c6bb02c33", size = 2071114, upload-time = "2026-05-06T13:40:35.416Z" }, + { url = "https://files.pythonhosted.org/packages/0f/da/7a263a96d965d9d0df5e8de8a475f33495451117035b09acb110288c381f/pydantic_core-2.46.4-cp311-cp311-win_arm64.whl", hash = "sha256:14f4c5d6db102bd796a627bbb3a17b4cf4574b9ae861d8b7c9a9661c6dd3362d", size = 2044298, upload-time = "2026-05-06T13:38:29.754Z" }, + { url = "https://files.pythonhosted.org/packages/ce/8c/af022f0af448d7747c5154288d46b5f2bc5f17366eaa0e23e9aa04d59f3b/pydantic_core-2.46.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3245406455a5d98187ec35530fd772b1d799b26667980872c8d4614991e2c4a2", size = 2106158, upload-time = "2026-05-06T13:38:57.215Z" }, + { url = "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:962ccbab7b642487b1d8b7df90ef677e03134cf1fd8880bf698649b22a69371f", size = 1951724, upload-time = "2026-05-06T13:37:02.697Z" }, + { url = "https://files.pythonhosted.org/packages/8e/bc/f47d1ff9cbb1620e1b5b697eef06010035735f07820180e74178226b27b3/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8233f2947cf85404441fd7e0085f53b10c93e0ee78611099b5c7237e36aacbf7", size = 1975742, upload-time = "2026-05-06T13:37:09.448Z" }, + { url = "https://files.pythonhosted.org/packages/5b/11/9b9a5b0306345664a2da6410877af6e8082481b5884b3ddd78d47c6013ce/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a233125ac121aa3ffba9a2b59edfc4a985a76092dc8279586ab4b71390875e7", size = 2052418, upload-time = "2026-05-06T13:37:38.234Z" }, + { url = "https://files.pythonhosted.org/packages/f1/b7/a65fec226f5d78fc39f4a13c4cc0c768c22b113438f60c14adc9d2865038/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b712b53160b79a5850310b912a5ef8e57e56947c8ad690c227f5c9d7e561712", size = 2232274, upload-time = "2026-05-06T13:38:27.753Z" }, + { url = "https://files.pythonhosted.org/packages/68/f0/92039db98b907ef49269a8271f67db9cb78ae2fc68062ef7e4e77adb5f61/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9401557acd873c3a7f3eb9383edef8ac4968f9510e340f4808d427e75667e7b4", size = 2309940, upload-time = "2026-05-06T13:38:05.353Z" }, + { url = "https://files.pythonhosted.org/packages/5f/97/2aab507d3d00ca626e8e57c1eac6a79e4e5fbcc63eb99733ff55d1717f65/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:926c9541b14b12b1681dca8a0b75feb510b06c6341b70a8e500c2fdcff837cce", size = 2094516, upload-time = "2026-05-06T13:39:10.577Z" }, + { url = "https://files.pythonhosted.org/packages/22/37/a8aca44d40d737dde2bc05b3c6c07dff0de07ce6f82e9f3167aeaf4d5dea/pydantic_core-2.46.4-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:56cb4851bcaf3d117eddcef4fe66afd750a50274b0da8e22be256d10e5611987", size = 2136854, upload-time = "2026-05-06T13:40:22.59Z" }, + { url = "https://files.pythonhosted.org/packages/24/99/fcef1b79238c06a8cbec70819ac722ba76e02bc8ada9b0fd66eba40da01b/pydantic_core-2.46.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c68fcd102d71ea85c5b2dfac3f4f8476eff42a9e078fd5faefff6d145063536b", size = 2180306, upload-time = "2026-05-06T13:40:10.666Z" }, + { url = "https://files.pythonhosted.org/packages/ae/6c/fc44000918855b42779d007ae63b0532794739027b2f417321cddbc44f6a/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b2f69dec1725e79a012d920df1707de5caf7ed5e08f3be4435e25803efc47458", size = 2190044, upload-time = "2026-05-06T13:40:43.231Z" }, + { url = "https://files.pythonhosted.org/packages/6b/65/d9cadc9f1920d7a127ad2edba16c1db7916e59719285cd6c94600b0080ba/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:8d0820e8192167f80d88d64038e609c31452eeca865b4e1d9950a27a4609b00b", size = 2329133, upload-time = "2026-05-06T13:39:57.365Z" }, + { url = "https://files.pythonhosted.org/packages/d0/cf/c873d91679f3a30bcf5e7ac280ce5573483e72295307685120d0d5ad3416/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fbdb89b3e1c94a30cc5edfce477c6e6a5dc4d8f84665b455c27582f211a1c72c", size = 2374464, upload-time = "2026-05-06T13:38:06.976Z" }, + { url = "https://files.pythonhosted.org/packages/47/bd/6f2fc8188f31bf10590f1e98e7b306336161fac930a8c514cd7bd828c7dc/pydantic_core-2.46.4-cp312-cp312-win32.whl", hash = "sha256:9aa768456404a8bf48a4406685ac2bec8e72b62c69313734fa3b73cf33b3a894", size = 1974823, upload-time = "2026-05-06T13:40:47.985Z" }, + { url = "https://files.pythonhosted.org/packages/40/8c/985c1d41ea1107c2534abd9870e4ed5c8e7669b5c308297835c001e7a1c4/pydantic_core-2.46.4-cp312-cp312-win_amd64.whl", hash = "sha256:e9c26f834c65f5752f3f06cb08cb86a913ceb7274d0db6e267808a708b46bc89", size = 2072919, upload-time = "2026-05-06T13:39:21.153Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ba/f463d006e0c47373ca7ec5e1a261c59dc01ef4d62b2657af925fb0deee3a/pydantic_core-2.46.4-cp312-cp312-win_arm64.whl", hash = "sha256:4fc73cb559bdb54b1134a706a2802a4cddd27a0633f5abb7e53056268751ac6a", size = 2027604, upload-time = "2026-05-06T13:39:03.753Z" }, + { url = "https://files.pythonhosted.org/packages/51/a2/5d30b469c5267a17b39dec53208222f76a8d351dfac4af661888c5aee77d/pydantic_core-2.46.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5d5902252db0d3cedf8d4a1bc68f70eeb430f7e4c7104c8c476753519b423008", size = 2106306, upload-time = "2026-05-06T13:37:48.029Z" }, + { url = "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c94f0688e7b8d0a67abf40e57a7eaaecd17cc9586706a31b76c031f63df052b4", size = 1951906, upload-time = "2026-05-06T13:37:17.012Z" }, + { url = "https://files.pythonhosted.org/packages/03/d5/fd02da45b659668b05923b17ba3a0100a0a3d5541e3bd8fcc4ecb711309e/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f027324c56cd5406ca49c124b0db10e56c69064fec039acc571c29020cc87c76", size = 1976802, upload-time = "2026-05-06T13:37:35.113Z" }, + { url = "https://files.pythonhosted.org/packages/21/f2/95727e1368be3d3ed485eaab7adbd7dda408f33f7a36e8b48e0144002b91/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e739fee756ba1010f8bcccb534252e85a35fe45ae92c295a06059ce58b74ccd3", size = 2052446, upload-time = "2026-05-06T13:37:12.313Z" }, + { url = "https://files.pythonhosted.org/packages/9c/86/5d99feea3f77c7234b8718075b23db11532773c1a0dbd9b9490215dc2eeb/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d56801be94b86a9da183e5f3766e6310752b99ff647e38b09a9500d88e46e76", size = 2232757, upload-time = "2026-05-06T13:39:01.149Z" }, + { url = "https://files.pythonhosted.org/packages/d2/3a/508ac615935ef7588cf6d9e9b91309fdc2da751af865e02a9098de88258c/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2412e734dcb48da14d4e4006b82b46b74f2518b8a26ee7e58c6844a6cd6d03c4", size = 2309275, upload-time = "2026-05-06T13:37:41.406Z" }, + { url = "https://files.pythonhosted.org/packages/07/f8/41db9de19d7987d6b04715a02b3b40aea467000275d9d758ffaa31af7d50/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9551187363ffc0de2a00b2e47c25aeaeb1020b69b668762966df15fc5659dd5a", size = 2094467, upload-time = "2026-05-06T13:39:18.847Z" }, + { url = "https://files.pythonhosted.org/packages/2c/e2/f35033184cb11d0052daf4416e8e10a502ea2ac006fc4f459aee872727d1/pydantic_core-2.46.4-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0186750b482eefa11d7f435892b09c5c606193ef3375bcf94aa00ae6bfb66262", size = 2134417, upload-time = "2026-05-06T13:40:17.944Z" }, + { url = "https://files.pythonhosted.org/packages/7e/7b/6ceeb1cc90e193862f444ebe373d8fdf613f0a82572dde03fb10734c6c71/pydantic_core-2.46.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5855698a4856556d86e8e6cd8434bc3ac0314ee8e12089ae0e143f64c6256e4e", size = 2179782, upload-time = "2026-05-06T13:40:32.618Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f2/c8d7773ede6af08036423a00ae0ceffce266c3c52a096c435d68c896083f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cbaf13819775b7f769bf4a1f066cb6df7a28d4480081a589828ef190226881cd", size = 2188782, upload-time = "2026-05-06T13:36:51.018Z" }, + { url = "https://files.pythonhosted.org/packages/59/31/0c864784e31f09f05cdd87606f08923b9c9e7f6e51dd27f20f62f975ce9f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:633147d34cf4550417f12e2b1a0383973bdf5cdfde212cb09e9a581cf10820be", size = 2328334, upload-time = "2026-05-06T13:40:37.764Z" }, + { url = "https://files.pythonhosted.org/packages/c2/eb/4f6c8a41efa30baa755590f4141abf3a8c370fab610915733e74134a7270/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:82cf5301172168103724d49a1444d3378cb20cdee30b116a1bd6031236298a5d", size = 2372986, upload-time = "2026-05-06T13:39:34.152Z" }, + { url = "https://files.pythonhosted.org/packages/5b/24/b375a480d53113860c299764bfe9f349a3dc9108b3adc0d7f0d786492ebf/pydantic_core-2.46.4-cp313-cp313-win32.whl", hash = "sha256:9fa8ae11da9e2b3126c6426f147e0fba88d96d65921799bb30c6abd1cb2c97fb", size = 1973693, upload-time = "2026-05-06T13:37:55.072Z" }, + { url = "https://files.pythonhosted.org/packages/7e/e8/cff247591966f2d22ec8c003cd7587e27b7ba7b81ab2fb888e3ab75dc285/pydantic_core-2.46.4-cp313-cp313-win_amd64.whl", hash = "sha256:6b3ace8194b0e5204818c92802dcdca7fc6d88aabbb799d7c795540d9cd6d292", size = 2071819, upload-time = "2026-05-06T13:38:49.139Z" }, + { url = "https://files.pythonhosted.org/packages/c6/1a/f4aee670d5670e9e148e0c82c7db98d780be566c6e6a97ee8035528ca0b3/pydantic_core-2.46.4-cp313-cp313-win_arm64.whl", hash = "sha256:184c081504d17f1c1066e430e117142b2c77d9448a97f7b65c6ac9fd9aee238d", size = 2027411, upload-time = "2026-05-06T13:40:45.796Z" }, + { url = "https://files.pythonhosted.org/packages/8d/74/228a26ddad29c6672b805d9fd78e8d251cd04004fa7eed0e622096cd0250/pydantic_core-2.46.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:428e04521a40150c85216fc8b85e8d39fece235a9cf5e383761238c7fa9b96fb", size = 2102079, upload-time = "2026-05-06T13:38:41.019Z" }, + { url = "https://files.pythonhosted.org/packages/ad/1f/8970b150a4b4365623ae00fc88603491f763c627311ae8031e3111356d6e/pydantic_core-2.46.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23ace664830ee0bfe014a0c7bc248b1f7f25ed7ad103852c317624a1083af462", size = 1952179, upload-time = "2026-05-06T13:36:59.812Z" }, + { url = "https://files.pythonhosted.org/packages/95/30/5211a831ae054928054b2f79731661087a2bc5c01e825c672b3a4a8f1b3e/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce5c1d2a8b27468f433ca974829c44060b8097eedc39933e3c206a90ee49c4a9", size = 1978926, upload-time = "2026-05-06T13:37:39.933Z" }, + { url = "https://files.pythonhosted.org/packages/57/e9/689668733b1eb67adeef047db3c2e8788fcf65a7fd9c9e2b46b7744fe245/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7283d57845ecf5a163403eb0702dfc220cc4fbdd18919cb5ccea4f95ee1cdab4", size = 2046785, upload-time = "2026-05-06T13:38:01.995Z" }, + { url = "https://files.pythonhosted.org/packages/60/d9/6715260422ff50a2109878fd24d948a6c3446bb2664f34ee78cd972b3acd/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8daafc69c93ee8a0204506a3b6b30f586ef54028f52aeeeb5c4cfc5184fd5914", size = 2228733, upload-time = "2026-05-06T13:40:50.371Z" }, + { url = "https://files.pythonhosted.org/packages/18/ae/fdb2f64316afca925640f8e70bb1a564b0ec2721c1389e25b8eb4bf9a299/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd2213145bcc2ba85884d0ac63d222fece9209678f77b9b4d76f054c561adb28", size = 2307534, upload-time = "2026-05-06T13:37:21.531Z" }, + { url = "https://files.pythonhosted.org/packages/89/1d/8eff589b45bb8190a9d12c49cfad0f176a5cbd1534908a6b5125e2886239/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a5f930472650a82629163023e630d160863fce524c616f4e5186e5de9d9a49b", size = 2099732, upload-time = "2026-05-06T13:39:31.942Z" }, + { url = "https://files.pythonhosted.org/packages/06/d5/ee5a3366637fee41dee51a1fc91562dcf12ddbc68fda34e6b253da2324bb/pydantic_core-2.46.4-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:c1b3f518abeca3aa13c712fd202306e145abf59a18b094a6bafb2d2bbf59192c", size = 2129627, upload-time = "2026-05-06T13:37:25.033Z" }, + { url = "https://files.pythonhosted.org/packages/94/33/2414be571d2c6a6c4d08be21f9292b6d3fdb08949a97b6dfe985017821db/pydantic_core-2.46.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a7dd0b3ee80d90150e3495a3a13ac34dbcbfd4f012996a6a1d8900e91b5c0fb", size = 2179141, upload-time = "2026-05-06T13:37:14.046Z" }, + { url = "https://files.pythonhosted.org/packages/7b/79/7daa95be995be0eecc4cf75064cb33f9bbbfe3fe0158caf2f0d4a996a5c7/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:3fb702cd90b0446a3a1c5e470bfa0dd23c0233b676a9099ddcc964fa6ca13898", size = 2184325, upload-time = "2026-05-06T13:36:53.615Z" }, + { url = "https://files.pythonhosted.org/packages/9f/cb/d0a382f5c0de8a222dc61c65348e0ce831b1f68e0a018450d31c2cace3a5/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b8458003118a712e66286df6a707db01c52c0f52f7db8e4a38f0da1d3b94fc4e", size = 2323990, upload-time = "2026-05-06T13:40:29.971Z" }, + { url = "https://files.pythonhosted.org/packages/05/db/d9ba624cc4a5aced1598e88c04fdbd8310c8a69b9d38b9a3d39ce3a61ed7/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:372429a130e469c9cd698925ce5fc50940b7a1336b0d82038e63d5bbc4edc519", size = 2369978, upload-time = "2026-05-06T13:37:23.027Z" }, + { url = "https://files.pythonhosted.org/packages/f2/20/d15df15ba918c423461905802bfd2981c3af0bfa0e40d05e13edbfa48bc3/pydantic_core-2.46.4-cp314-cp314-win32.whl", hash = "sha256:85bb3611ff1802f3ee7fdd7dbff26b56f343fb432d57a4728fdd49b6ef35e2f4", size = 1966354, upload-time = "2026-05-06T13:38:03.499Z" }, + { url = "https://files.pythonhosted.org/packages/fc/b6/6b8de4c0a7d7ab3004c439c80c5c1e0a3e8d78bbae19379b01960383d9e5/pydantic_core-2.46.4-cp314-cp314-win_amd64.whl", hash = "sha256:811ff8e9c313ab425368bcbb36e5c4ebd7108c2bbf4e4089cfbb0b01eff63fac", size = 2072238, upload-time = "2026-05-06T13:39:40.807Z" }, + { url = "https://files.pythonhosted.org/packages/32/36/51eb763beec1f4cf59b1db243a7dcc39cbb41230f050a09b9d69faaf0a48/pydantic_core-2.46.4-cp314-cp314-win_arm64.whl", hash = "sha256:bfec22eab3c8cc2ceec0248aec886624116dc079afa027ecc8ad4a7e62010f8a", size = 2018251, upload-time = "2026-05-06T13:37:26.72Z" }, + { url = "https://files.pythonhosted.org/packages/e8/91/855af51d625b23aa987116a19e231d2aaef9c4a415273ddc189b79a45fee/pydantic_core-2.46.4-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:af8244b2bef6aaad6d92cda81372de7f8c8d36c9f0c3ea36e827c60e7d9467a0", size = 2099593, upload-time = "2026-05-06T13:39:47.682Z" }, + { url = "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a4330cdbc57162e4b3aa303f588ba752257694c9c9be3e7ebb11b4aca659b5d", size = 1935226, upload-time = "2026-05-06T13:40:40.428Z" }, + { url = "https://files.pythonhosted.org/packages/e8/e7/1955d28d1afc56dd4b3ad7cc0cf39df1b9852964cf16e5d13912756d6d6b/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c61fc04a3d840155ff08e475a04809278972fe6aef51e2720554e96367e34b", size = 1974605, upload-time = "2026-05-06T13:37:32.029Z" }, + { url = "https://files.pythonhosted.org/packages/93/e2/3fedbf0ba7a22850e6e9fd78117f1c0f10f950182344d8a6c535d468fdd8/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c50f2528cf200c5eed56faf3f4e22fcd5f38c157a8b78576e6ba3168ec35f000", size = 2030777, upload-time = "2026-05-06T13:38:55.239Z" }, + { url = "https://files.pythonhosted.org/packages/f8/61/46be275fcaaba0b4f5b9669dd852267ce1ff616592dccf7a7845588df091/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0cbe8b01f948de4286c74cdd6c667aceb38f5c1e26f0693b3983d9d74887c65e", size = 2236641, upload-time = "2026-05-06T13:37:08.096Z" }, + { url = "https://files.pythonhosted.org/packages/60/db/12e93e46a8bac9988be3c016860f83293daea8c716c029c9ace279036f2f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:617d7e2ca7dcb8c5cf6bcb8c59b8832c94b36196bbf1cbd1bfb56ed341905edd", size = 2286404, upload-time = "2026-05-06T13:40:20.221Z" }, + { url = "https://files.pythonhosted.org/packages/e2/4a/4d8b19008f38d31c53b8219cfedc2e3d5de5fe99d90076b7e767de29274f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7027560ee92211647d0d34e3f7cd6f50da56399d26a9c8ad0da286d3869a53f3", size = 2109219, upload-time = "2026-05-06T13:38:12.153Z" }, + { url = "https://files.pythonhosted.org/packages/88/70/3cbc40978fefb7bb09c6708d40d4ad1a5d70fd7213c3d17f971de868ec1f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:f99626688942fb746e545232e7726926f3be91b5975f8b55327665fafda991c7", size = 2110594, upload-time = "2026-05-06T13:40:02.971Z" }, + { url = "https://files.pythonhosted.org/packages/9d/20/b8d36736216e29491125531685b2f9e61aa5b4b2599893f8268551da3338/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc3e9034a63de20e15e8ade85358bc6efc614008cab72898b4b4952bea0509ff", size = 2159542, upload-time = "2026-05-06T13:39:27.506Z" }, + { url = "https://files.pythonhosted.org/packages/1d/a2/367df868eb584dacf6bf82a389272406d7178e301c4ac82545ab98bc2dd9/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:97e7cf2be5c77b7d1a9713a05605d49460d02c6078d38d8bef3cbe323c548424", size = 2168146, upload-time = "2026-05-06T13:38:31.93Z" }, + { url = "https://files.pythonhosted.org/packages/c1/b8/4460f77f7e201893f649a29ab355dddd3beee8a97bcb1a320db414f9a06e/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:3bf92c5d0e00fefaab325a4d27828fe6b6e2a21848686b5b60d2d9eeb09d76c6", size = 2306309, upload-time = "2026-05-06T13:37:44.717Z" }, + { url = "https://files.pythonhosted.org/packages/64/c4/be2639293acd87dc8ddbcec41a73cee9b2ebf996fe6d892a1a74e88ad3f7/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:3ecbc122d18468d06ca279dc26a8c2e2d5acb10943bb35e36ae92096dc3b5565", size = 2369736, upload-time = "2026-05-06T13:37:05.645Z" }, + { url = "https://files.pythonhosted.org/packages/30/a6/9f9f380dbb301f67023bf8f707aaa75daadf84f7152d95c410fd7e81d994/pydantic_core-2.46.4-cp314-cp314t-win32.whl", hash = "sha256:e846ae7835bf0703ae43f534ab79a867146dadd59dc9ca5c8b53d5c8f7c9ef02", size = 1955575, upload-time = "2026-05-06T13:38:51.116Z" }, + { url = "https://files.pythonhosted.org/packages/40/1f/f1eb9eb350e795d1af8586289746f5c5677d16043040d63710e22abc43c9/pydantic_core-2.46.4-cp314-cp314t-win_amd64.whl", hash = "sha256:2108ba5c1c1eca18030634489dc544844144ee36357f2f9f780b93e7ddbb44b5", size = 2051624, upload-time = "2026-05-06T13:38:21.672Z" }, + { url = "https://files.pythonhosted.org/packages/f6/d2/42dd53d0a85c27606f316d3aa5d2869c4e8470a5ed6dec30e4a1abe19192/pydantic_core-2.46.4-cp314-cp314t-win_arm64.whl", hash = "sha256:4fcbe087dbc2068af7eda3aa87634eba216dbda64d1ae73c8684b621d33f6596", size = 2017325, upload-time = "2026-05-06T13:40:52.723Z" }, + { url = "https://files.pythonhosted.org/packages/ee/a4/73995fd4ebbb46ba0ee51e6fa049b8f02c40daebb762208feda8a6b7894d/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:14d4edf427bdcf950a8a02d7cb44a08614388dd6e1bdcbf4f67504fa7887da9c", size = 2111589, upload-time = "2026-05-06T13:37:10.817Z" }, + { url = "https://files.pythonhosted.org/packages/fb/7f/f37d3a5e8bfcc2e403f5c57a730f2d815693fb42119e8ea48b3789335af1/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:0ce40cd7b21210e99342afafbd4d0f76d784eb5b1d60f3bdc566be4983c6c73b", size = 1944552, upload-time = "2026-05-06T13:36:56.717Z" }, + { url = "https://files.pythonhosted.org/packages/15/3c/d7eb777b3ff43e8433a4efb39a17aa8fd98a4ee8561a24a67ef5db07b2d6/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90884113d8b48f760e9587002789ddd741e76ab9f89518cd1e43b1f1a52ec44b", size = 1982984, upload-time = "2026-05-06T13:39:06.207Z" }, + { url = "https://files.pythonhosted.org/packages/63/87/70b9f40170a81afd55ca26c9b2acb25c20d64bcfbf888fafecb3ba077d4c/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66ce7632c22d837c95301830e111ad0128a32b8207533b60896a96c4915192ea", size = 2138417, upload-time = "2026-05-06T13:39:45.476Z" }, + { url = "https://files.pythonhosted.org/packages/9d/1d/8987ad40f65ae1432753072f214fb5c74fe47ffbd0698bb9cbbb585664f8/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:1d8ba486450b14f3b1d63bc521d410ec7565e52f887b9fb671791886436a42f7", size = 2095527, upload-time = "2026-05-06T13:39:52.283Z" }, + { url = "https://files.pythonhosted.org/packages/64/d3/84c282a7eee1d3ac4c0377546ef5a1ea436ce26840d9ac3b7ed54a377507/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:3009f12e4e90b7f88b4f9adb1b0c4a3d58fe7820f3238c190047209d148026df", size = 1936024, upload-time = "2026-05-06T13:40:15.671Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ca/eac61596cdeb4d7e174d3dc0bd8a6238f14f75f97a24e7b7db4c7e7340a0/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad785e92e6dc634c21555edc8bd6b64957ab844541bcb96a1366c202951ae526", size = 1990696, upload-time = "2026-05-06T13:38:34.717Z" }, + { url = "https://files.pythonhosted.org/packages/fa/c3/7c8b240552251faf6b3a957db200fcfbbcec36763c050428b601e0c9b83b/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00c603d540afdd6b80eb39f078f33ebd46211f02f33e34a32d9f053bba711de0", size = 2147590, upload-time = "2026-05-06T13:39:29.883Z" }, + { url = "https://files.pythonhosted.org/packages/11/cb/428de0385b6c8d44b716feba566abfacfbd23ee3c4439faa789a1456242f/pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0c563b08bca408dc7f65f700633d8442fffb2421fc47b8101377e9fd65051ff0", size = 2112782, upload-time = "2026-05-06T13:37:04.016Z" }, + { url = "https://files.pythonhosted.org/packages/0b/b5/6a17bdadd0fc1f170adfd05a20d37c832f52b117b4d9131da1f41bb097ce/pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:db06ffe51636ffe9ca531fe9023dd64bdd794be8754cb5df57c5498ae5b518a7", size = 1952146, upload-time = "2026-05-06T13:39:43.092Z" }, + { url = "https://files.pythonhosted.org/packages/2a/dc/03734d80e362cd43ef65428e9de77c730ce7f2f11c60d2b1e1b39f0fbf99/pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:133878133d271ade3d41d1bfb2a45ec38dbdbda40bc065921c6b04e4630127e2", size = 2134492, upload-time = "2026-05-06T13:36:58.124Z" }, + { url = "https://files.pythonhosted.org/packages/de/df/5e5ffc085ed07cc22d298134d3d911c63e91f6a0eb91fe646750a3209910/pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9bc519fbf2b7578398853d815009ae5e4d4603d12f4e3f91da8c06852d3da3e9", size = 2156604, upload-time = "2026-05-06T13:37:49.88Z" }, + { url = "https://files.pythonhosted.org/packages/81/44/6e112a4253e56f5705467cbab7ab5e91ee7398ba3d56d358635958893d3e/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c7a7bd4e39e8e4c12c39cd480356842b6a8a06e41b23a55a5e3e191718838ddf", size = 2183828, upload-time = "2026-05-06T13:37:43.053Z" }, + { url = "https://files.pythonhosted.org/packages/ac/ad/5565071e937d8e752842ac241463944c9eb14c87e2d269f2658a5bd05e98/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:d396ec2b979760aaf3218e76c24e65bd0aca24983298653b3a9d7a45f9e47b30", size = 2310000, upload-time = "2026-05-06T13:37:56.694Z" }, + { url = "https://files.pythonhosted.org/packages/4f/c3/66883a5cec183e7fba4d024b4cbbe61851a63750ef606b0afecc46d1f2bf/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:86e1a4418c6cd97d60c95c71164158eaf7324fae7b0923264016baa993eba6fc", size = 2361286, upload-time = "2026-05-06T13:40:05.667Z" }, + { url = "https://files.pythonhosted.org/packages/4b/2d/69abac8f838090bbecd5df894befb2c2619e7996a98ddb949db9f3b93225/pydantic_core-2.46.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:d51026d73fcfd93610abc7b27789c26b313920fcfb20e27462d74a7f8b06e983", size = 2193071, upload-time = "2026-05-06T13:38:08.682Z" }, +] + +[[package]] +name = "pydantic-settings" +version = "2.14.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/07/60/1d1e59c9c90d54591469ada7d268251f71c24bdb765f1a8a832cee8c6653/pydantic_settings-2.14.1.tar.gz", hash = "sha256:e874d3bec7e787b0c9958277956ed9b4dd5de6a80e162188fdaff7c5e26fd5fa", size = 235551, upload-time = "2026-05-08T13:40:06.542Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ae/8d/f1af3832f5e6eb13ba94ee809e72b8ecb5eef226d27ee0bef7d963d943c7/pydantic_settings-2.14.1-py3-none-any.whl", hash = "sha256:6e3c7edfd8277687cdc598f56e5cff0e9bfff0910a3749deaa8d4401c3a2b9de", size = 60964, upload-time = "2026-05-08T13:40:04.958Z" }, +] + +[[package]] +name = "pygments" +version = "2.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, +] + +[[package]] +name = "pyparsing" +version = "3.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, +] + +[[package]] +name = "pytest" +version = "9.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165, upload-time = "2026-04-07T17:16:18.027Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16.13Z" }, +] + +[[package]] +name = "pytest-asyncio" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/90/2c/8af215c0f776415f3590cac4f9086ccefd6fd463befeae41cd4d3f193e5a/pytest_asyncio-1.3.0.tar.gz", hash = "sha256:d7f52f36d231b80ee124cd216ffb19369aa168fc10095013c6b014a34d3ee9e5", size = 50087, upload-time = "2025-11-10T16:07:47.256Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5", size = 15075, upload-time = "2025-11-10T16:07:45.537Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "python-dotenv" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" }, +] + +[[package]] +name = "python-multipart" +version = "0.0.30" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4b/82/c8cd43a6e0719bf5a3b034f6726dd701f75829c08944c83d4b95d02ed0e8/python_multipart-0.0.30.tar.gz", hash = "sha256:0edfe0475c1f46ddd3ff7785a626f6118af32bdcf359bb21260367313bb32118", size = 46316, upload-time = "2026-05-31T19:24:55.198Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1c/fd/0318007beb234790993d3ec5afd051d1dbceb733e81e3afe2b981ece3f37/python_multipart-0.0.30-py3-none-any.whl", hash = "sha256:830964def8c90607ac5daa00514e3987815865713ade8d20febc9177ac0c3c5b", size = 29730, upload-time = "2026-05-31T19:24:53.814Z" }, +] + +[[package]] +name = "pytz" +version = "2026.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ff/46/dd499ec9038423421951e4fad73051febaa13d2df82b4064f87af8b8c0c3/pytz-2026.2.tar.gz", hash = "sha256:0e60b47b29f21574376f218fe21abc009894a2321ea16c6754f3cad6eb7cdd6a", size = 320861, upload-time = "2026-05-04T01:35:29.667Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/dd/96da98f892250475bdf2328112d7468abdd4acc7b902b6af23f4ed958ea0/pytz-2026.2-py2.py3-none-any.whl", hash = "sha256:04156e608bee23d3792fd45c94ae47fae1036688e75032eea2e3bf0323d1f126", size = 510141, upload-time = "2026-05-04T01:35:27.408Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, +] + +[[package]] +name = "regex" +version = "2026.5.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/0e/49aee608ad09480e7fd276898c99ec6192985fa331abe4eb3a986094490b/regex-2026.5.9.tar.gz", hash = "sha256:a8234aa23ec39894bfe4a3f1b85616a7032481964a13ac6fc9f10de4f6fca270", size = 416074, upload-time = "2026-05-09T23:15:19.37Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/dc/c1f2df4027e82fc54b5a473e4b250f5139faca49a0fbe29a48668d228f34/regex-2026.5.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ccf5249114cc3e772ecdd88a98a86eca0fd74c61ce32a94743758c083fc05d48", size = 489445, upload-time = "2026-05-09T23:12:06.111Z" }, + { url = "https://files.pythonhosted.org/packages/03/d2/59f01110660081cce9c0bc30ebd0b5ee250dacf658e3248ed92f01e0e8ee/regex-2026.5.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46f1326ca6e65b0879d23ca302c0f2415aad42ff0309b9c818e7949fe19a41d8", size = 291271, upload-time = "2026-05-09T23:12:07.731Z" }, + { url = "https://files.pythonhosted.org/packages/58/b6/14b2c84ff90ddb370c81d27503f4a0fcf071496416f4855f6cc8c5d81c35/regex-2026.5.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ef31cbfe458e21c6122ba8150ff060e0c7789ed0d26eb423f25472584920b555", size = 289212, upload-time = "2026-05-09T23:12:09.266Z" }, + { url = "https://files.pythonhosted.org/packages/03/d0/4db86529117320de0c84afd90e70bb47434625875e34fcef9d8c127c5b16/regex-2026.5.9-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:992604d02e6d9c6d786c24a706a71ecffe1020fc1ef264044474cd81fa2c3919", size = 792310, upload-time = "2026-05-09T23:12:11.416Z" }, + { url = "https://files.pythonhosted.org/packages/07/78/fe4800cd322f862ecffd2d553409b20d80650e5ed71b9d178f853d020b82/regex-2026.5.9-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c9411dd64ca95477225734a93dfc8583b51916b8d5942f99d6cac21e09965451", size = 861721, upload-time = "2026-05-09T23:12:13.681Z" }, + { url = "https://files.pythonhosted.org/packages/b5/d0/b3618a895dd8feb897c61bb2954edd265e1767d82a01d53065d5871127a3/regex-2026.5.9-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3dd4a3ff360dfb836fecdb93a4598f9d6e2ac81e3e397125145c6221bf58cf4c", size = 906460, upload-time = "2026-05-09T23:12:15.443Z" }, + { url = "https://files.pythonhosted.org/packages/33/6f/1481597e859ef19508b345eec4afd1416ed6e6b459c75a64026ef193aecf/regex-2026.5.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2a661a7d270a61f7cf460caee8b9fa2d5ef9e5c681234bcb9e0fe14f488e7dfc", size = 799843, upload-time = "2026-05-09T23:12:16.892Z" }, + { url = "https://files.pythonhosted.org/packages/73/59/955734c803f59108deccba3597ae440c76b62a652733c0006e6243758420/regex-2026.5.9-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f079e50a0d3cc3cd5091fa9ff45869a2e6b2cd35895731edafb0327901a8d86d", size = 773610, upload-time = "2026-05-09T23:12:19.127Z" }, + { url = "https://files.pythonhosted.org/packages/68/8f/70c04a236d651c81881dac42ef8538bddda6121434509d0a22d9e601503b/regex-2026.5.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4ebe8f0b5ec5a5024dc4a4c59f444c4e9afc5f2abdbb8962065b75d27fb971f9", size = 781645, upload-time = "2026-05-09T23:12:20.806Z" }, + { url = "https://files.pythonhosted.org/packages/1d/96/05c7434d88185e5d27fe54aeb74df86bd77cd79f52f0b4eae54faa8fea70/regex-2026.5.9-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:97cf3bc1b7d7d2306772ec07366c80d9df00ff79e79cea32898883a646d2fae2", size = 854473, upload-time = "2026-05-09T23:12:22.465Z" }, + { url = "https://files.pythonhosted.org/packages/4e/c1/6e3d8202d981f3117004bf341ee74893ba4ba8a9fbaf4b94615846550a08/regex-2026.5.9-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0f9eede6a5cbdc02d4978090186390936e1776a7d1359b21e41014c609880bcf", size = 763311, upload-time = "2026-05-09T23:12:24.351Z" }, + { url = "https://files.pythonhosted.org/packages/93/c7/e7737f1526b3fb32bd4c337fd6c71c3ebb5c8296fc34d11197e0955d2e35/regex-2026.5.9-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:01f0f5f55f4b64dacec85dc116d3c05fd23ad3ff037bbc73a2085775953c2611", size = 844593, upload-time = "2026-05-09T23:12:26.341Z" }, + { url = "https://files.pythonhosted.org/packages/a5/27/0daffb1a535bb39f422c3d200f4ab023c71110ad66a32b366bee708baba0/regex-2026.5.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1268eddd8486dc561d08eee1156e40aa3a8fe10f4bdec8fa653b455fcbffd12c", size = 789167, upload-time = "2026-05-09T23:12:27.975Z" }, + { url = "https://files.pythonhosted.org/packages/ce/fc/294fe4fac4f2ed67207b17471815870c1c45b3a489e08e0ac96daea16ef6/regex-2026.5.9-cp311-cp311-win32.whl", hash = "sha256:8676474c07469d6f33dd1085ca2cd45f65785f32518f2b20e36d9953ca07f994", size = 266249, upload-time = "2026-05-09T23:12:30.141Z" }, + { url = "https://files.pythonhosted.org/packages/d0/b0/8dce459f6245bcf8f6e9f23ac9569f1a0f15c131cc0745e82b43226204cf/regex-2026.5.9-cp311-cp311-win_amd64.whl", hash = "sha256:246de9d60aa3f8538b519834dd95cbf276ea263d6a7bd5a3666dc3fa0230505b", size = 278423, upload-time = "2026-05-09T23:12:31.676Z" }, + { url = "https://files.pythonhosted.org/packages/db/8d/f9aeff6ad63a3ef720386f2907e6d34a35a510a6e498ebad28b0fb3f6ab6/regex-2026.5.9-cp311-cp311-win_arm64.whl", hash = "sha256:d726ca3f0d76969bf1e8e477d160d3d666bbf999f6860bd314889e5345782046", size = 270420, upload-time = "2026-05-09T23:12:33.194Z" }, + { url = "https://files.pythonhosted.org/packages/50/9b/6550044bc44e17c84d312c031c2ec42fbdb6a4ec4e29093be3a172d08772/regex-2026.5.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:57eeeb05db7979413dec5438f2db21d7ecbba787cde7a711df1a6f6df672aa06", size = 490451, upload-time = "2026-05-09T23:12:34.72Z" }, + { url = "https://files.pythonhosted.org/packages/1e/95/fc7ba4303b5a0f92446a12ee6778ef2c6c799233f5060042a31bf390cfe9/regex-2026.5.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:398c521292f4c7fb807001dcd54694d3a1fcafc179a36ad9cc56f98df85930b6", size = 292112, upload-time = "2026-05-09T23:12:36.285Z" }, + { url = "https://files.pythonhosted.org/packages/54/4b/ee27938d1b2c443e89a9a10e00d2d19aa5ee300cd3d61140644e93bb083e/regex-2026.5.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f7a7c26137296beba7784de6eba69c6a93a63ccebc385e4962fe67e267a91225", size = 289599, upload-time = "2026-05-09T23:12:38.089Z" }, + { url = "https://files.pythonhosted.org/packages/d8/dd/ba103dc19614e25f3880800ca67ce093d6e21b325d72b8383c7bf906e9fa/regex-2026.5.9-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6441cc660d76107934a09c22167200839a0e89604a6297f78a974e66e931d2c0", size = 796732, upload-time = "2026-05-09T23:12:40.062Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e7/f035b4fd858b050b0080bf302968dc0f59ba34e391872d54936758e6844e/regex-2026.5.9-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:91328f1c23d47595ca3ef0a7557fa129c5a23404b775c770697d2f35b33e0107", size = 865440, upload-time = "2026-05-09T23:12:42.059Z" }, + { url = "https://files.pythonhosted.org/packages/0a/51/8cd301ecc899aea28124357f729f4272f44de7806fc7ca02490bfbe253e8/regex-2026.5.9-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:93a7860539414dddaefba2b40f8771765ae17949d4c7182b876ce429e11a8309", size = 912329, upload-time = "2026-05-09T23:12:44.373Z" }, + { url = "https://files.pythonhosted.org/packages/cc/1e/3fbe2fa1e8cebd62f3bb7d3321cff1640aca2e240b51d9bd624aad949260/regex-2026.5.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd2810d22146b6d838acc5ec15602cb6b47920aa4e33015df3868eedfd20bab8", size = 801239, upload-time = "2026-05-09T23:12:46.268Z" }, + { url = "https://files.pythonhosted.org/packages/17/2f/6f6008682bf2cf98040a0d3153a8e557b6ab728d7713d045cee4ce544ab8/regex-2026.5.9-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:daff2bdbaf1d23e52fdff7c0b7bc2048b68f978df6a4d107ac981f94caef2e66", size = 777054, upload-time = "2026-05-09T23:12:48.051Z" }, + { url = "https://files.pythonhosted.org/packages/19/2b/eee0d20a6842ba04df4b8847a920b57ef56853f14ef85405473e586b605a/regex-2026.5.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4eeb011098fcb77af513dcef521a3dbecbf8849b1e38940759d293b7a93f5026", size = 785098, upload-time = "2026-05-09T23:12:49.851Z" }, + { url = "https://files.pythonhosted.org/packages/4a/98/6fc1e6410feefb92159edaed5041992bfe390e8d26c721865434acbca558/regex-2026.5.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ea9c8ecfa1b73c73b626534d6626e5340d429630943672b8480724f44e84b962", size = 860095, upload-time = "2026-05-09T23:12:51.666Z" }, + { url = "https://files.pythonhosted.org/packages/18/a3/bd855e0f2cb1a978ecf6fa6bb69632dd9c3f6ea3b81cde62fde14c9daec7/regex-2026.5.9-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:cd2846168eb9ee3c513902bc8225409cb1caab31d04728b145171fa1625d9621", size = 765762, upload-time = "2026-05-09T23:12:53.413Z" }, + { url = "https://files.pythonhosted.org/packages/dc/66/0ae8c092e60b14c79d24f8e0b7f0aea5bfbffdcab00b5483d13404d3c3a5/regex-2026.5.9-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:39617fb0cde9c0e6306dc70e3bfc096f3da793219879f7ae7aa341a69fbdcf6d", size = 852100, upload-time = "2026-05-09T23:12:55.256Z" }, + { url = "https://files.pythonhosted.org/packages/21/de/8dfde60fc1b21c946a893ba273403b72617edb261370cb1087099a83f088/regex-2026.5.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fd03c4f0e33280d15cae17159b899245d6b7c53d21def19b263b39655061f5ce", size = 789479, upload-time = "2026-05-09T23:12:57.573Z" }, + { url = "https://files.pythonhosted.org/packages/c3/1c/bdcc98f9a4af4fdd166c74941174619ccff4726d3ce32faa8e9a2ecd38dd/regex-2026.5.9-cp312-cp312-win32.whl", hash = "sha256:164eba9b755ea6f244b0d881196fbc1fac09714e9782c9e2732b813142033c8e", size = 266699, upload-time = "2026-05-09T23:12:59.14Z" }, + { url = "https://files.pythonhosted.org/packages/78/87/240d36864f9e48ace85f72e79ced97ceb7f27ce87739a947dcb834b4e6bc/regex-2026.5.9-cp312-cp312-win_amd64.whl", hash = "sha256:86f40a5d6444db30a125c9c9177e6b25dad981cbc37451fd838f145e6edac92e", size = 277783, upload-time = "2026-05-09T23:13:00.789Z" }, + { url = "https://files.pythonhosted.org/packages/4f/b5/7b30f312b0669dff5beebe5b0989dc2d1a312b1a44fab852199c387a5b96/regex-2026.5.9-cp312-cp312-win_arm64.whl", hash = "sha256:96f5f58b54a063d7ea9dca08e1cf57bfe10499c4d579ee672da284f57f5f0070", size = 270513, upload-time = "2026-05-09T23:13:02.426Z" }, + { url = "https://files.pythonhosted.org/packages/aa/da/797e91ecec6f84135da778ddce78c20e0af5d2a15c26f87a81bc3eadb6db/regex-2026.5.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d626b84406444b165fc0ba981604edea39f0588ff1f92baa23fe50799ea9afdb", size = 490303, upload-time = "2026-05-09T23:13:04.382Z" }, + { url = "https://files.pythonhosted.org/packages/44/da/bf30abaaa737b58f4a4b8c4a03659e02fd92092c822e0197ed9e0daab917/regex-2026.5.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d7bdc0ab8f3dd7e1b4f9ab88634e13374669db86bb3c72e8292f07ae313f539f", size = 292019, upload-time = "2026-05-09T23:13:06.022Z" }, + { url = "https://files.pythonhosted.org/packages/2d/e7/d0eaf5713828417b9e5648cf81fa9bacd4961f6ab98c380c2034f8716e35/regex-2026.5.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a8820737949116ffff55fe18f9fc644530063ba6ebfcb8314239416e78f1347c", size = 289468, upload-time = "2026-05-09T23:13:08.214Z" }, + { url = "https://files.pythonhosted.org/packages/d3/9b/b3fdd62b003baa1a9b593cd8c8699c9651c2e80cc21a5c715707983c42d7/regex-2026.5.9-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa0fbdbac82cb3e4450d0ccde7d7a35607f4cb2dd9fba4b8b69bfaf8c9fa6aed", size = 796749, upload-time = "2026-05-09T23:13:10.573Z" }, + { url = "https://files.pythonhosted.org/packages/d4/30/66ab84588765f5b4b271a9ca09ef7ce2b87caa95176ec3d2ad65d7bc4902/regex-2026.5.9-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:57e8915c7986aa33d25e4d3629cef711cd2863f2961b10409f0c04cb8b7d9020", size = 865445, upload-time = "2026-05-09T23:13:12.523Z" }, + { url = "https://files.pythonhosted.org/packages/1a/89/f05169e8588aac365f35ffc7f3bc3184f095ef4cfded7cfaa3c7fd5dbd89/regex-2026.5.9-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:508f56a89ba9cb26e4168cbc37dbd60a28d82430a9e18ad1d25fe0883c314ca2", size = 912322, upload-time = "2026-05-09T23:13:14.281Z" }, + { url = "https://files.pythonhosted.org/packages/30/e1/c93444052cf41581f3c884ab3fb5823daf0992f11cd4388d4275ca610558/regex-2026.5.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6d189041f15691cfa2b6c4290448ec221244d225b3f5fe9e7771b34ffcdf6e2", size = 801269, upload-time = "2026-05-09T23:13:16.569Z" }, + { url = "https://files.pythonhosted.org/packages/50/fe/0cf96b882f540e62e8b9956599798203d599c44cf4c77917ca27400ff69b/regex-2026.5.9-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e82db382b44d0111b22601c509c89f64434816c9e0eef9d1989cda8cc6ff1c04", size = 777085, upload-time = "2026-05-09T23:13:18.675Z" }, + { url = "https://files.pythonhosted.org/packages/23/5c/d78d4924e7fc875557b9e9b768423925fdfaac5549d06da7810019a9bd26/regex-2026.5.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2acfb48634f64996b57f90f39afa692ff362162722581921fe92239a59960f3c", size = 785153, upload-time = "2026-05-09T23:13:20.525Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e0/5214774090e7b4524dcea3e3c4aa74141d43043f8beb49c1599db1c8b53a/regex-2026.5.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d29eebfc9525db68cad3c97eedd7f754fa265aa5cd0cf4f863b2421e1b48fc9f", size = 860164, upload-time = "2026-05-09T23:13:22.263Z" }, + { url = "https://files.pythonhosted.org/packages/6e/e1/4a57a83350319b1271f0d7a249b8672513ed928b237a741631270de6caea/regex-2026.5.9-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:debb893095e944091c16e641a6e33c1b0f4cb61ab945ec5afbf53ce7068834d8", size = 765731, upload-time = "2026-05-09T23:13:24.277Z" }, + { url = "https://files.pythonhosted.org/packages/12/f4/499e74a20c156fc75836ee04a72a38d1a063978f600937f9760467beb1b0/regex-2026.5.9-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d659eee77986549c9ea45b861c7567e44d6287c3dc9a4565478853f7b9fe2ff6", size = 852062, upload-time = "2026-05-09T23:13:26.125Z" }, + { url = "https://files.pythonhosted.org/packages/5b/92/7eebc0d0a01e78629695f342ba17e0deaff8fb45e79cc0d7b98287da6e3e/regex-2026.5.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2efa205e6d98b24d1f3ab395c11aa15cdf10935bca283d0285e0499c284fba21", size = 789577, upload-time = "2026-05-09T23:13:27.814Z" }, + { url = "https://files.pythonhosted.org/packages/05/a4/018e71f7d2ad48c1ebe6d3ae0026f9b7cb4802fd15c7cc02fdf724355102/regex-2026.5.9-cp313-cp313-win32.whl", hash = "sha256:f3844f134e834076677dd369976e9f5068679fcb8e50102fdf6b7ac96a3ec127", size = 266691, upload-time = "2026-05-09T23:13:29.549Z" }, + { url = "https://files.pythonhosted.org/packages/e6/1d/861a93719fb9ee7dbfc3761b3797b7a3e112a5d42c6129459d2d741be9b5/regex-2026.5.9-cp313-cp313-win_amd64.whl", hash = "sha256:3527bb4942d2c14552155406cdedd906567456821848aed1cb4933a391bf5eca", size = 277747, upload-time = "2026-05-09T23:13:31.859Z" }, + { url = "https://files.pythonhosted.org/packages/d9/c6/0a2436ae4da1ba76e51cb98943c6838a9a721faa40ebe2dce07694ae34e3/regex-2026.5.9-cp313-cp313-win_arm64.whl", hash = "sha256:56a33f191f17d8c417f99945ebdc1e691d3af9605d86ec68c7e54a57e3e17af6", size = 270500, upload-time = "2026-05-09T23:13:33.525Z" }, + { url = "https://files.pythonhosted.org/packages/e8/e9/d21346f7b60ed58789371358ed66b09d00f832e1bd7c06e55d9da5679882/regex-2026.5.9-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:01f28d868834624c934b8d2e0aa1c8341337e37831f4a012f18a5afcba4cbaf3", size = 494172, upload-time = "2026-05-09T23:13:35.935Z" }, + { url = "https://files.pythonhosted.org/packages/c4/43/fd1177a2032037c681baecdb3422ee4e1424aec4e4f470ef47793d325274/regex-2026.5.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:48036f6374aaa79eb3b754ec29c61d1c6b1606749d705a13f8854fa2539671f6", size = 293952, upload-time = "2026-05-09T23:13:38.307Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7d/9fbf919768368d3f8a4f6c692cf2aa61e482b2b81ec6a298ace4cbf02480/regex-2026.5.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b96350aa424e79d4fd6b567b344dcbe2b2d6bfc48dfe7717587e1fa6d43da6ff", size = 292314, upload-time = "2026-05-09T23:13:40.353Z" }, + { url = "https://files.pythonhosted.org/packages/e2/6c/e41bfeecb589716843e7c4df09ba46ff2a42961457afece19059d85caeef/regex-2026.5.9-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8f3af7a4903c5c04a11a196a5aa75cdd7dd3f8508132f9fb3259d9f5908e3b88", size = 811681, upload-time = "2026-05-09T23:13:42.543Z" }, + { url = "https://files.pythonhosted.org/packages/87/83/a5c1c525fba0aa656e88ad0face0b1829788ef4c2fb6b26df58aa1151b84/regex-2026.5.9-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7e87577720152d2caae19fe2baaf1f8d5ca12091e9e229f03915c37d1e4b9178", size = 871135, upload-time = "2026-05-09T23:13:44.326Z" }, + { url = "https://files.pythonhosted.org/packages/18/d4/80882e799e440dd878b0979cbebf8fa4d54624a332c83037c7a701649e3f/regex-2026.5.9-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c8b9b9d294cfea3cd19c718ade7cc93492b2c4991abd9a68d0b3477ae6d8e100", size = 917265, upload-time = "2026-05-09T23:13:47.295Z" }, + { url = "https://files.pythonhosted.org/packages/ae/ff/8db60211e2286e396aad7dc7725356c502bff0901ea05bd6cdc2e1a042b9/regex-2026.5.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:728d8bfd28a8845c8b6bc5dc7ce010453d206396786c0765c2740cb65f37791e", size = 816311, upload-time = "2026-05-09T23:13:49.885Z" }, + { url = "https://files.pythonhosted.org/packages/4c/47/742ef579c61730f8d268e5cf1f9ce0e37e2ea041ad0f5644724f2378e463/regex-2026.5.9-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7e30b874d341fac767d7df5a0870540541c2c054b80cfaac116e8d367a8a7ff2", size = 785498, upload-time = "2026-05-09T23:13:52.25Z" }, + { url = "https://files.pythonhosted.org/packages/7f/ab/cb0999802dcb0fb95b1ab005e8d4163d8afdd67efc2cb6b6630ac13f8cb1/regex-2026.5.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:fd190e88a895a8901325fad284a3f74ea52b1da8525b76cc811fa9b1edf0ce2b", size = 801348, upload-time = "2026-05-09T23:13:54.127Z" }, + { url = "https://files.pythonhosted.org/packages/7d/62/8ca59a24c55bc34d166eefaf3717bd77772f329fdbf984d86581e0a3571c/regex-2026.5.9-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:8e76e8161ad00694cfce6767d5dea860c6391ac5b83e5c3a39661e696f11fc7e", size = 866493, upload-time = "2026-05-09T23:13:56.067Z" }, + { url = "https://files.pythonhosted.org/packages/8d/3d/30f2ae62cef3278bb5bb821f467277a55fb73f01032cf85997e15e8289a8/regex-2026.5.9-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ddda5340e6c01a293027dd46232fa79eaff1b48058ce7a98f572b6445b088041", size = 772811, upload-time = "2026-05-09T23:13:57.867Z" }, + { url = "https://files.pythonhosted.org/packages/d8/ae/7d2089bcd78ad0c0161bc684339df50032acb438a7bd3305e7ddb1193cec/regex-2026.5.9-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:205109e96b3cf5adf8f4cd62bedde9487feb282b9497a3535451e5a24cd706a0", size = 856584, upload-time = "2026-05-09T23:13:59.679Z" }, + { url = "https://files.pythonhosted.org/packages/a9/29/92ff47f75990131ea4f24ba17819e5a9d141e10819807e09addd73409af6/regex-2026.5.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dfbe4579b9f08036aa7d101d1835437a20783574ac66327e6b29b4018a138081", size = 803453, upload-time = "2026-05-09T23:14:01.978Z" }, + { url = "https://files.pythonhosted.org/packages/04/99/eff29f1037dcab36702c9ee5d6858cf1ce2336ea8ea2987f64245b99ea5e/regex-2026.5.9-cp313-cp313t-win32.whl", hash = "sha256:ed2c9e8068b614c574d8d30e543d617cf5379b0535d46f97ef00e904745a08b5", size = 269951, upload-time = "2026-05-09T23:14:03.661Z" }, + { url = "https://files.pythonhosted.org/packages/0e/9d/8870b8981d27b22cda77bb26a5ac7ebfa9c7d9e0dea195a834a82380e748/regex-2026.5.9-cp313-cp313t-win_amd64.whl", hash = "sha256:b46b0f094dc1d3b90356c85a0bd2c9bafc4a6a190b9d6f8ddd5a033b6e088ed4", size = 281240, upload-time = "2026-05-09T23:14:05.56Z" }, + { url = "https://files.pythonhosted.org/packages/72/b1/3379415e8f135c13ac551353397cc4fe97b4978f3cac73c5fcbcded548b8/regex-2026.5.9-cp313-cp313t-win_arm64.whl", hash = "sha256:872acc074bd29ffc9913ecdfedf6ea77502312ca44a4aa0d3779089c6069d8de", size = 272383, upload-time = "2026-05-09T23:14:07.843Z" }, + { url = "https://files.pythonhosted.org/packages/13/3e/9c3cd292d8808b3645a2ce517e200179b6d0e903f176300bd8b542e14de5/regex-2026.5.9-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:1bd7587a2948b4085195d5a3374eaf4a425dc3e55784c038175355ecf3bbbf8a", size = 490376, upload-time = "2026-05-09T23:14:09.64Z" }, + { url = "https://files.pythonhosted.org/packages/60/70/d43ee8a2ca0a8b68d167f21658b85520ac0574617c7f320367c5047f7556/regex-2026.5.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:dea2e88e1cce4522496cce630e11e67b98b7076620bc4336c3f674bc21a375f4", size = 291964, upload-time = "2026-05-09T23:14:11.424Z" }, + { url = "https://files.pythonhosted.org/packages/21/91/9d50b433828d8e74196904e168a43abf1e6e88b2a15d47ed742456720c37/regex-2026.5.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2099f7e7ff7b6aa3192312650a56e91cc091e49d50b04e4f6f8b6e28b3b27f1c", size = 289682, upload-time = "2026-05-09T23:14:13.123Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d2/b835e3cafbb9d977736912436259ff551d60919f7d7b3d37d46659c63564/regex-2026.5.9-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecd353045824e4477562a2ac718c25799cdaaa41f7aa925a806a8a3e6848a5b9", size = 796996, upload-time = "2026-05-09T23:14:14.923Z" }, + { url = "https://files.pythonhosted.org/packages/2c/a6/9f992d00019166b9de01c546dd4549bc679f2a68df11b877740b0760b7c2/regex-2026.5.9-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:65c8c8c37377794bd5b2f3ebe51919042bf17aec802e23c833d89782ed0c78af", size = 866089, upload-time = "2026-05-09T23:14:17.757Z" }, + { url = "https://files.pythonhosted.org/packages/e0/08/4d32af657e049b19cb62b02e46e38fe1518797bfb2203ee93a510b21b0dc/regex-2026.5.9-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5b73ab8afcf66c622db143d1c6fda4e58e4d537ee4f125229ad47b1ab80f34c0", size = 911530, upload-time = "2026-05-09T23:14:20.353Z" }, + { url = "https://files.pythonhosted.org/packages/d9/27/2af43dd1dc201d1fecefda64a45f4ad0995855b92724f795a777b402ee69/regex-2026.5.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0de5cf193997384ed2ca6f1cd4f78055b255d93d82d5a8cd6ba0d11c10b167e4", size = 800643, upload-time = "2026-05-09T23:14:22.265Z" }, + { url = "https://files.pythonhosted.org/packages/a4/dd/23a249047013b5321d4a60c4d2437462086f601b061776a525e5fba2a59f/regex-2026.5.9-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d641a8c9a61618047796d572a39a79b26167b0411d2c3031937b2fe2d081e2cf", size = 777223, upload-time = "2026-05-09T23:14:24.179Z" }, + { url = "https://files.pythonhosted.org/packages/94/6a/e85ed9538cd19586d0465076a4578a12e093ce776d15f3f8ce92733a8dd6/regex-2026.5.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:24b2355ef5cc9aa5b8f07d17704face1c166fdcc2290fa7bd6e6c925655a8346", size = 785760, upload-time = "2026-05-09T23:14:26.065Z" }, + { url = "https://files.pythonhosted.org/packages/2a/c4/f25473209438638e947c55f9156fd8f236f74169229028cc99116380868e/regex-2026.5.9-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:a24852d3c29ad9e47593593d8a247c44ccc3d0548ef12c822d6ed0810affe676", size = 860891, upload-time = "2026-05-09T23:14:28.17Z" }, + { url = "https://files.pythonhosted.org/packages/f9/f7/f4f86e3c74419c37370e91f150ae0c2ef7d34b2e0e4cdd5da046a02e4022/regex-2026.5.9-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:916714069da19329ef7de197dcbc77bb3104145c7c2c864dbfbe318f46b88b14", size = 765891, upload-time = "2026-05-09T23:14:30.06Z" }, + { url = "https://files.pythonhosted.org/packages/26/70/704d8e13765939146b1cd0ef4e2feb71d7929727d2290f026eed10095955/regex-2026.5.9-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:fa411799ca8da32a8d38d020a88faa5b6f91657d284761352940ecf9f7c3bbdd", size = 851380, upload-time = "2026-05-09T23:14:32.123Z" }, + { url = "https://files.pythonhosted.org/packages/26/29/1a13582a8460038edc38e49f64ceb0dd7c60f5caba77571f4bf6601965d9/regex-2026.5.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1e6da47d679b7010ef27556b6e0f99771b744936db1792a10ceac6547ae1503e", size = 789350, upload-time = "2026-05-09T23:14:34.799Z" }, + { url = "https://files.pythonhosted.org/packages/73/56/3dcafe34fc72e271d62ad9a291801e88a1457bb251c132f15fcc2e5aad1a/regex-2026.5.9-cp314-cp314-win32.whl", hash = "sha256:98bd73080e8756255137e1bd3f3f00295bbc5aa383c0e0f973920e9134d7c4ad", size = 272130, upload-time = "2026-05-09T23:14:36.729Z" }, + { url = "https://files.pythonhosted.org/packages/d0/9c/02eebf0be95efe416c664db7fb8b6b05b7a0b06a7544f2884f2558b0526f/regex-2026.5.9-cp314-cp314-win_amd64.whl", hash = "sha256:ff8d372ac2acdc048d1c19916f27ee61bc5722728458ba6ca5052f2c72d51763", size = 280999, upload-time = "2026-05-09T23:14:39.126Z" }, + { url = "https://files.pythonhosted.org/packages/70/5a/1dd1abee76cb7a846a0bcf42fdc87e5720c3c33c24f3e37814310a513d9f/regex-2026.5.9-cp314-cp314-win_arm64.whl", hash = "sha256:e1d93bf647916292e8edcec150c07ddf3dc50179ccaf770c04a7f9e452155372", size = 273500, upload-time = "2026-05-09T23:14:41.059Z" }, + { url = "https://files.pythonhosted.org/packages/86/c1/c5f619b0057a7965cb78ec559c1d7a45ce8c99a35bea95483d64959a93d9/regex-2026.5.9-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:83d0ee4a57d1c87cb549e195ec300b8f0ec3a82eba66d835e4e2ed8634fe4499", size = 494269, upload-time = "2026-05-09T23:14:42.869Z" }, + { url = "https://files.pythonhosted.org/packages/05/2c/5d01f1aee33de4bbe60c8452945bfc8477ca7c5ae4450f6bfe711036cb36/regex-2026.5.9-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d3d7eb5c9a7f6df82ed3cfac9beb93882a5cbcb5b8b157b56cb2b3b276574ac1", size = 293954, upload-time = "2026-05-09T23:14:44.822Z" }, + { url = "https://files.pythonhosted.org/packages/7a/fe/e8988b2ae2108c6ef71bd4aa8d87fbe257976dd0810e826cd75f701c68b6/regex-2026.5.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:075160bf16658e16d35233300b8453aac25de4cbea808d22348b6979668e924d", size = 292405, upload-time = "2026-05-09T23:14:47.211Z" }, + { url = "https://files.pythonhosted.org/packages/79/34/d2b0937faa7859263f7f0a3c6b103a1296306be6952dc173d0154e9a2f49/regex-2026.5.9-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:45375819235558a4ff1c4971dc32881f022613abdb180128f5cb4768c1765a1c", size = 811855, upload-time = "2026-05-09T23:14:49.21Z" }, + { url = "https://files.pythonhosted.org/packages/80/fe/daf53a47457a8486db66c66c01ceb9c2303eecee3f87197f1e77eb1a736d/regex-2026.5.9-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ead4b163ac30a29574510cd4b3e2e985ac5290c05fc7095557d6a5f403fc31b5", size = 871189, upload-time = "2026-05-09T23:14:51.555Z" }, + { url = "https://files.pythonhosted.org/packages/1c/75/058fc4470cbfbf57d800aff1a0022b929a3f9fa553ee10a0cdf2070eb31f/regex-2026.5.9-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8c6e4218fbdfbcd4f6c19efca40930d24a621bf4b48cb76bc6640543bd28ef20", size = 917485, upload-time = "2026-05-09T23:14:53.633Z" }, + { url = "https://files.pythonhosted.org/packages/88/e7/179cfda3a28bc843b5c6cfe7f79f23489c791ed95f151083803660878432/regex-2026.5.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6351571c8a42b505eb555c0dc47d740d0fb66977dc142919eea6f4325b7c56a0", size = 816369, upload-time = "2026-05-09T23:14:56.198Z" }, + { url = "https://files.pythonhosted.org/packages/41/90/6f0cc422071688266d344fca8462d787cba0a2c144acb25721f9a61ec265/regex-2026.5.9-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:002205cafd2a9e78c6290c7d1df277bf3277b3b7a30e0b4bb0dac2e2e3f7cb2d", size = 785869, upload-time = "2026-05-09T23:14:58.602Z" }, + { url = "https://files.pythonhosted.org/packages/02/67/a31f1760f09c27b251ef39e9beb541f462cf977381d067faa764c2c0e393/regex-2026.5.9-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8abd33fef90b2a9efac5557d6033ca82d1195ed3a15fea5af15ba7b463c6a63b", size = 801427, upload-time = "2026-05-09T23:15:00.642Z" }, + { url = "https://files.pythonhosted.org/packages/e3/c4/1a80654597b6bc1e1ea0494824c31200e8a956abe290afae9b19a166a148/regex-2026.5.9-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:31037c82eccb44b7ea2e9e221d7c01429430e989a1f4b91ea5a855f6017b509a", size = 866482, upload-time = "2026-05-09T23:15:03.384Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/960724e06482c08466ff5611e242e86f80062949cdf6b4b9cc317b9dd93d/regex-2026.5.9-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:5604dfd046dc37eca90250fc3be938b076c8059fa772ac0ed6f499b0f0fb0415", size = 773022, upload-time = "2026-05-09T23:15:05.625Z" }, + { url = "https://files.pythonhosted.org/packages/50/a8/a9979c3e7918280e93159ebcab5ef1a65116dd4f3bd6091be0eae4a126e8/regex-2026.5.9-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0e1b1b4e496afbb24f4a62aba855ee4f88f25578927697b340702e48c9ee6bc2", size = 856642, upload-time = "2026-05-09T23:15:07.966Z" }, + { url = "https://files.pythonhosted.org/packages/fe/d4/a9b732f2f0072c0ab12227483abb24fffcb9f73f8a2b203df0a6d0434735/regex-2026.5.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:be3372b9df6ddecff6486d37e19095a7b4973137caf5512407a89f4455361f41", size = 803552, upload-time = "2026-05-09T23:15:10.215Z" }, + { url = "https://files.pythonhosted.org/packages/d5/fe/1b3113817447a1d4155e4ac76d2e072f42c0bcba2f43fa8a0e756ea2cd91/regex-2026.5.9-cp314-cp314t-win32.whl", hash = "sha256:3ddd90103f9e5c471c49c7852ecc1fe27c7e45eb99e977aefe7caa4e779f4f58", size = 275746, upload-time = "2026-05-09T23:15:12.609Z" }, + { url = "https://files.pythonhosted.org/packages/92/73/93d42045302636c91f2e5ef588b65b84b01428f28ec77de256b1dfdfbe5c/regex-2026.5.9-cp314-cp314t-win_amd64.whl", hash = "sha256:ca518ed29c46eecba6010b15f1b9a479314d2de409536e71b6a13aa04e3b8a77", size = 285685, upload-time = "2026-05-09T23:15:15.086Z" }, + { url = "https://files.pythonhosted.org/packages/da/80/35b4c33c804a165a7f55289afda3ea9e3eb6d15800341a2d66455c0f1f30/regex-2026.5.9-cp314-cp314t-win_arm64.whl", hash = "sha256:5e41809d2683fcde7d5a8c87a6567ba1fb1ce0de9f31bff578de00a4b2d76daa", size = 275713, upload-time = "2026-05-09T23:15:16.98Z" }, +] + +[[package]] +name = "requests" +version = "2.34.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" }, +] + +[[package]] +name = "ruff" +version = "0.15.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/8a/8bce2894573e9dae6ff4d77fe34ad727d79b9e6238ad288c5638990d90f6/ruff-0.15.14.tar.gz", hash = "sha256:48e866b165be4a9bdbf310f7d3c9a07edef2fe8cd63ffeb4e00bb590506ebf9f", size = 4700910, upload-time = "2026-05-21T14:34:55.177Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/c8/74a92c6ff9fcfb4f1f947126d3ebee8389276e161ecc85de5bda7cda51bd/ruff-0.15.14-py3-none-linux_armv6l.whl", hash = "sha256:8dd2db9416e487c8d4b01fa7056bb02c4d05969d4f8d17a08c229c2f4ff3c108", size = 10739177, upload-time = "2026-05-21T14:34:37.332Z" }, + { url = "https://files.pythonhosted.org/packages/45/91/254a35c20acc38a7223c9d2d594af12e794432464f2cdeb52af1dc4a892d/ruff-0.15.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:be4ff55af755bd71a00ab3dc6bd7ffc467bd76e0df6881e286c2e3d23e8fb43b", size = 11144969, upload-time = "2026-05-21T14:34:43.978Z" }, + { url = "https://files.pythonhosted.org/packages/56/9e/d13e40f83b8d0a94430e6778ce1d94a43b38cf2efe63278bdd2b4c65abbf/ruff-0.15.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:48d5909d7d06276ce7dde6d32bfa4b0d4cb2651145cd8ee4b440722cbc77832f", size = 10478207, upload-time = "2026-05-21T14:34:48.378Z" }, + { url = "https://files.pythonhosted.org/packages/8d/f1/b15a7839fa4f332f8acec78e20564f26bb2d866e3d21710b877fd0263000/ruff-0.15.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca8cbfa94c4f90984a67561978602746d4cd27103568f745fa90eee3f0d4107d", size = 10818459, upload-time = "2026-05-21T14:34:22.318Z" }, + { url = "https://files.pythonhosted.org/packages/45/33/53d651177f84f94b400a0e27f8824eeada3dddc9d5ee8aeb048f4352a520/ruff-0.15.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a6bbc0333f1ab053423bcbf6226477d266ca7cec7738c4c8e3f55647803f3c4", size = 10541800, upload-time = "2026-05-21T14:34:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/b8/a6/868f87e0bf9786ed24b5d0d0ad8676b8a94fd1912f42cddf9cfc7857818a/ruff-0.15.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a24a4f7605d7003a6674d4387651effd939dead3fddd0f36561eb77a9a2e542", size = 11342149, upload-time = "2026-05-21T14:34:46.365Z" }, + { url = "https://files.pythonhosted.org/packages/a7/8b/38cd5c19faffdcc05a408d2b78edccc69492ab9720eadb49ea15ef80d768/ruff-0.15.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:049b5326e53ed80978f2fc041a280603f69dd6b0c95464342a2bb4572d9d9e2f", size = 12212563, upload-time = "2026-05-21T14:34:28.579Z" }, + { url = "https://files.pythonhosted.org/packages/3e/4d/a3c5b874a556d5731e3e657aaf04311bb76f0a5c3ec220ed43051be6b64b/ruff-0.15.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4ed42e6696c8dfa5f06728e6441993901f548eb92d73bc472cb5a38d1395fbf", size = 11493299, upload-time = "2026-05-21T14:34:41.836Z" }, + { url = "https://files.pythonhosted.org/packages/1e/c0/56472c251d09858a53e51efbd485b09e1995d8731668b76d52e5dd6ee0f1/ruff-0.15.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:715c543cf450c4888251f91c52f1942a800541d9bddd7ac060aa4e6b77ae7cba", size = 11455931, upload-time = "2026-05-21T14:34:57.276Z" }, + { url = "https://files.pythonhosted.org/packages/2c/4a/e2e7b4d8dbf233d4eace59c75bc3435fa6d8bd3bae82d351d4e4300c0fd1/ruff-0.15.14-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:72ebab6013ec887d439d8b7593737a0a4ffb06d45d209d4e4bf2e92813082d3f", size = 11400794, upload-time = "2026-05-21T14:34:39.773Z" }, + { url = "https://files.pythonhosted.org/packages/97/c7/83c0539fe34c3e09136204d1e75d6052492364e0b3cb05e9465423f567d7/ruff-0.15.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:49072d36abdbe97a8dd7f480afe9c675699c0c495d4c84076e2c1203c4550581", size = 10804759, upload-time = "2026-05-21T14:34:31.045Z" }, + { url = "https://files.pythonhosted.org/packages/86/a6/18f2bfc095a2ab4a78745644e428205532ce6653a5d0fa8501572891534d/ruff-0.15.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:958522aee105068640c2c2ceae08f413ae44d922f52a1374ac13d6a96032fc93", size = 10539517, upload-time = "2026-05-21T14:34:53.064Z" }, + { url = "https://files.pythonhosted.org/packages/54/3a/5a8b3b69c654d4e4bf1d246ac5b49cbcdac6eaab6905925f8915f31e3b80/ruff-0.15.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f3707da619a143a2e8830e2abab8224478d69ace2d28cb6c20543ae97c36bf61", size = 11065169, upload-time = "2026-05-21T14:34:24.484Z" }, + { url = "https://files.pythonhosted.org/packages/ed/c5/8864e4e7925b836ea354b31d57641ec03830564e281a8b6f061f8c3e0ec1/ruff-0.15.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:bb01d645694e3ec0102105d07ef2d53703970407d59c04e59d3ba0b7a1d53553", size = 11560214, upload-time = "2026-05-21T14:34:50.975Z" }, + { url = "https://files.pythonhosted.org/packages/36/38/012bf76752e1f89ed50b77b99532d90f3a3e287bc7918e1fc0948ac866ac/ruff-0.15.14-py3-none-win32.whl", hash = "sha256:6d0c1ad2a0ab718d39b6d8fd2217981ce4d625cd96a720095f798fb47d8b13e6", size = 10805548, upload-time = "2026-05-21T14:34:33.453Z" }, + { url = "https://files.pythonhosted.org/packages/d1/b7/4ea2c170f10ad760fff2a5250beb18897719dc8b52b53a24cddbb9dd3f19/ruff-0.15.14-py3-none-win_amd64.whl", hash = "sha256:802342981e056db3851a7836e5b070f8f15f67d4a685ae2a6160939d364b2902", size = 11939523, upload-time = "2026-05-21T14:34:18.077Z" }, + { url = "https://files.pythonhosted.org/packages/62/d5/bc97ff895ec35cf3925d4bd60f3b39d822f377a446906ec9bcc87405e59b/ruff-0.15.14-py3-none-win_arm64.whl", hash = "sha256:ff47b90a9ef6a40c9e2f3b479c1fb78531adf055b94c1eba0a7ba04b31951826", size = 11208607, upload-time = "2026-05-21T14:34:26.525Z" }, +] + +[[package]] +name = "schedule" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0c/91/b525790063015759f34447d4cf9d2ccb52cdee0f1dd6ff8764e863bcb74c/schedule-1.2.2.tar.gz", hash = "sha256:15fe9c75fe5fd9b9627f3f19cc0ef1420508f9f9a46f45cd0769ef75ede5f0b7", size = 26452, upload-time = "2024-06-18T20:03:14.633Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/a7/84c96b61fd13205f2cafbe263cdb2745965974bdf3e0078f121dfeca5f02/schedule-1.2.2-py3-none-any.whl", hash = "sha256:5bef4a2a0183abf44046ae0d164cadcac21b1db011bdd8102e4a0c1e91e06a7d", size = 12220, upload-time = "2024-05-25T18:41:59.121Z" }, +] + +[[package]] +name = "scikit-learn" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "joblib" }, + { name = "numpy" }, + { name = "scipy" }, + { name = "threadpoolctl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0e/d4/40988bf3b8e34feec1d0e6a051446b1f66225f8529b9309becaeef62b6c4/scikit_learn-1.8.0.tar.gz", hash = "sha256:9bccbb3b40e3de10351f8f5068e105d0f4083b1a65fa07b6634fbc401a6287fd", size = 7335585, upload-time = "2025-12-10T07:08:53.618Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c9/92/53ea2181da8ac6bf27170191028aee7251f8f841f8d3edbfdcaf2008fde9/scikit_learn-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:146b4d36f800c013d267b29168813f7a03a43ecd2895d04861f1240b564421da", size = 8595835, upload-time = "2025-12-10T07:07:39.385Z" }, + { url = "https://files.pythonhosted.org/packages/01/18/d154dc1638803adf987910cdd07097d9c526663a55666a97c124d09fb96a/scikit_learn-1.8.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:f984ca4b14914e6b4094c5d52a32ea16b49832c03bd17a110f004db3c223e8e1", size = 8080381, upload-time = "2025-12-10T07:07:41.93Z" }, + { url = "https://files.pythonhosted.org/packages/8a/44/226142fcb7b7101e64fdee5f49dbe6288d4c7af8abf593237b70fca080a4/scikit_learn-1.8.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5e30adb87f0cc81c7690a84f7932dd66be5bac57cfe16b91cb9151683a4a2d3b", size = 8799632, upload-time = "2025-12-10T07:07:43.899Z" }, + { url = "https://files.pythonhosted.org/packages/36/4d/4a67f30778a45d542bbea5db2dbfa1e9e100bf9ba64aefe34215ba9f11f6/scikit_learn-1.8.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ada8121bcb4dac28d930febc791a69f7cb1673c8495e5eee274190b73a4559c1", size = 9103788, upload-time = "2025-12-10T07:07:45.982Z" }, + { url = "https://files.pythonhosted.org/packages/89/3c/45c352094cfa60050bcbb967b1faf246b22e93cb459f2f907b600f2ceda5/scikit_learn-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:c57b1b610bd1f40ba43970e11ce62821c2e6569e4d74023db19c6b26f246cb3b", size = 8081706, upload-time = "2025-12-10T07:07:48.111Z" }, + { url = "https://files.pythonhosted.org/packages/3d/46/5416595bb395757f754feb20c3d776553a386b661658fb21b7c814e89efe/scikit_learn-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:2838551e011a64e3053ad7618dda9310175f7515f1742fa2d756f7c874c05961", size = 7688451, upload-time = "2025-12-10T07:07:49.873Z" }, + { url = "https://files.pythonhosted.org/packages/90/74/e6a7cc4b820e95cc38cf36cd74d5aa2b42e8ffc2d21fe5a9a9c45c1c7630/scikit_learn-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5fb63362b5a7ddab88e52b6dbb47dac3fd7dafeee740dc6c8d8a446ddedade8e", size = 8548242, upload-time = "2025-12-10T07:07:51.568Z" }, + { url = "https://files.pythonhosted.org/packages/49/d8/9be608c6024d021041c7f0b3928d4749a706f4e2c3832bbede4fb4f58c95/scikit_learn-1.8.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:5025ce924beccb28298246e589c691fe1b8c1c96507e6d27d12c5fadd85bfd76", size = 8079075, upload-time = "2025-12-10T07:07:53.697Z" }, + { url = "https://files.pythonhosted.org/packages/dd/47/f187b4636ff80cc63f21cd40b7b2d177134acaa10f6bb73746130ee8c2e5/scikit_learn-1.8.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4496bb2cf7a43ce1a2d7524a79e40bc5da45cf598dbf9545b7e8316ccba47bb4", size = 8660492, upload-time = "2025-12-10T07:07:55.574Z" }, + { url = "https://files.pythonhosted.org/packages/97/74/b7a304feb2b49df9fafa9382d4d09061a96ee9a9449a7cbea7988dda0828/scikit_learn-1.8.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0bcfe4d0d14aec44921545fd2af2338c7471de9cb701f1da4c9d85906ab847a", size = 8931904, upload-time = "2025-12-10T07:07:57.666Z" }, + { url = "https://files.pythonhosted.org/packages/9f/c4/0ab22726a04ede56f689476b760f98f8f46607caecff993017ac1b64aa5d/scikit_learn-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:35c007dedb2ffe38fe3ee7d201ebac4a2deccd2408e8621d53067733e3c74809", size = 8019359, upload-time = "2025-12-10T07:07:59.838Z" }, + { url = "https://files.pythonhosted.org/packages/24/90/344a67811cfd561d7335c1b96ca21455e7e472d281c3c279c4d3f2300236/scikit_learn-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:8c497fff237d7b4e07e9ef1a640887fa4fb765647f86fbe00f969ff6280ce2bb", size = 7641898, upload-time = "2025-12-10T07:08:01.36Z" }, + { url = "https://files.pythonhosted.org/packages/03/aa/e22e0768512ce9255eba34775be2e85c2048da73da1193e841707f8f039c/scikit_learn-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0d6ae97234d5d7079dc0040990a6f7aeb97cb7fa7e8945f1999a429b23569e0a", size = 8513770, upload-time = "2025-12-10T07:08:03.251Z" }, + { url = "https://files.pythonhosted.org/packages/58/37/31b83b2594105f61a381fc74ca19e8780ee923be2d496fcd8d2e1147bd99/scikit_learn-1.8.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:edec98c5e7c128328124a029bceb09eda2d526997780fef8d65e9a69eead963e", size = 8044458, upload-time = "2025-12-10T07:08:05.336Z" }, + { url = "https://files.pythonhosted.org/packages/2d/5a/3f1caed8765f33eabb723596666da4ebbf43d11e96550fb18bdec42b467b/scikit_learn-1.8.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:74b66d8689d52ed04c271e1329f0c61635bcaf5b926db9b12d58914cdc01fe57", size = 8610341, upload-time = "2025-12-10T07:08:07.732Z" }, + { url = "https://files.pythonhosted.org/packages/38/cf/06896db3f71c75902a8e9943b444a56e727418f6b4b4a90c98c934f51ed4/scikit_learn-1.8.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8fdf95767f989b0cfedb85f7ed8ca215d4be728031f56ff5a519ee1e3276dc2e", size = 8900022, upload-time = "2025-12-10T07:08:09.862Z" }, + { url = "https://files.pythonhosted.org/packages/1c/f9/9b7563caf3ec8873e17a31401858efab6b39a882daf6c1bfa88879c0aa11/scikit_learn-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:2de443b9373b3b615aec1bb57f9baa6bb3a9bd093f1269ba95c17d870422b271", size = 7989409, upload-time = "2025-12-10T07:08:12.028Z" }, + { url = "https://files.pythonhosted.org/packages/49/bd/1f4001503650e72c4f6009ac0c4413cb17d2d601cef6f71c0453da2732fc/scikit_learn-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:eddde82a035681427cbedded4e6eff5e57fa59216c2e3e90b10b19ab1d0a65c3", size = 7619760, upload-time = "2025-12-10T07:08:13.688Z" }, + { url = "https://files.pythonhosted.org/packages/d2/7d/a630359fc9dcc95496588c8d8e3245cc8fd81980251079bc09c70d41d951/scikit_learn-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:7cc267b6108f0a1499a734167282c00c4ebf61328566b55ef262d48e9849c735", size = 8826045, upload-time = "2025-12-10T07:08:15.215Z" }, + { url = "https://files.pythonhosted.org/packages/cc/56/a0c86f6930cfcd1c7054a2bc417e26960bb88d32444fe7f71d5c2cfae891/scikit_learn-1.8.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:fe1c011a640a9f0791146011dfd3c7d9669785f9fed2b2a5f9e207536cf5c2fd", size = 8420324, upload-time = "2025-12-10T07:08:17.561Z" }, + { url = "https://files.pythonhosted.org/packages/46/1e/05962ea1cebc1cf3876667ecb14c283ef755bf409993c5946ade3b77e303/scikit_learn-1.8.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72358cce49465d140cc4e7792015bb1f0296a9742d5622c67e31399b75468b9e", size = 8680651, upload-time = "2025-12-10T07:08:19.952Z" }, + { url = "https://files.pythonhosted.org/packages/fe/56/a85473cd75f200c9759e3a5f0bcab2d116c92a8a02ee08ccd73b870f8bb4/scikit_learn-1.8.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:80832434a6cc114f5219211eec13dcbc16c2bac0e31ef64c6d346cde3cf054cb", size = 8925045, upload-time = "2025-12-10T07:08:22.11Z" }, + { url = "https://files.pythonhosted.org/packages/cc/b7/64d8cfa896c64435ae57f4917a548d7ac7a44762ff9802f75a79b77cb633/scikit_learn-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ee787491dbfe082d9c3013f01f5991658b0f38aa8177e4cd4bf434c58f551702", size = 8507994, upload-time = "2025-12-10T07:08:23.943Z" }, + { url = "https://files.pythonhosted.org/packages/5e/37/e192ea709551799379958b4c4771ec507347027bb7c942662c7fbeba31cb/scikit_learn-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf97c10a3f5a7543f9b88cbf488d33d175e9146115a451ae34568597ba33dcde", size = 7869518, upload-time = "2025-12-10T07:08:25.71Z" }, + { url = "https://files.pythonhosted.org/packages/24/05/1af2c186174cc92dcab2233f327336058c077d38f6fe2aceb08e6ab4d509/scikit_learn-1.8.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:c22a2da7a198c28dd1a6e1136f19c830beab7fdca5b3e5c8bba8394f8a5c45b3", size = 8528667, upload-time = "2025-12-10T07:08:27.541Z" }, + { url = "https://files.pythonhosted.org/packages/a8/25/01c0af38fe969473fb292bba9dc2b8f9b451f3112ff242c647fee3d0dfe7/scikit_learn-1.8.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:6b595b07a03069a2b1740dc08c2299993850ea81cce4fe19b2421e0c970de6b7", size = 8066524, upload-time = "2025-12-10T07:08:29.822Z" }, + { url = "https://files.pythonhosted.org/packages/be/ce/a0623350aa0b68647333940ee46fe45086c6060ec604874e38e9ab7d8e6c/scikit_learn-1.8.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:29ffc74089f3d5e87dfca4c2c8450f88bdc61b0fc6ed5d267f3988f19a1309f6", size = 8657133, upload-time = "2025-12-10T07:08:31.865Z" }, + { url = "https://files.pythonhosted.org/packages/b8/cb/861b41341d6f1245e6ca80b1c1a8c4dfce43255b03df034429089ca2a2c5/scikit_learn-1.8.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fb65db5d7531bccf3a4f6bec3462223bea71384e2cda41da0f10b7c292b9e7c4", size = 8923223, upload-time = "2025-12-10T07:08:34.166Z" }, + { url = "https://files.pythonhosted.org/packages/76/18/a8def8f91b18cd1ba6e05dbe02540168cb24d47e8dcf69e8d00b7da42a08/scikit_learn-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:56079a99c20d230e873ea40753102102734c5953366972a71d5cb39a32bc40c6", size = 8096518, upload-time = "2025-12-10T07:08:36.339Z" }, + { url = "https://files.pythonhosted.org/packages/d1/77/482076a678458307f0deb44e29891d6022617b2a64c840c725495bee343f/scikit_learn-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:3bad7565bc9cf37ce19a7c0d107742b320c1285df7aab1a6e2d28780df167242", size = 7754546, upload-time = "2025-12-10T07:08:38.128Z" }, + { url = "https://files.pythonhosted.org/packages/2d/d1/ef294ca754826daa043b2a104e59960abfab4cf653891037d19dd5b6f3cf/scikit_learn-1.8.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:4511be56637e46c25721e83d1a9cea9614e7badc7040c4d573d75fbe257d6fd7", size = 8848305, upload-time = "2025-12-10T07:08:41.013Z" }, + { url = "https://files.pythonhosted.org/packages/5b/e2/b1f8b05138ee813b8e1a4149f2f0d289547e60851fd1bb268886915adbda/scikit_learn-1.8.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:a69525355a641bf8ef136a7fa447672fb54fe8d60cab5538d9eb7c6438543fb9", size = 8432257, upload-time = "2025-12-10T07:08:42.873Z" }, + { url = "https://files.pythonhosted.org/packages/26/11/c32b2138a85dcb0c99f6afd13a70a951bfdff8a6ab42d8160522542fb647/scikit_learn-1.8.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c2656924ec73e5939c76ac4c8b026fc203b83d8900362eb2599d8aee80e4880f", size = 8678673, upload-time = "2025-12-10T07:08:45.362Z" }, + { url = "https://files.pythonhosted.org/packages/c7/57/51f2384575bdec454f4fe4e7a919d696c9ebce914590abf3e52d47607ab8/scikit_learn-1.8.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15fc3b5d19cc2be65404786857f2e13c70c83dd4782676dd6814e3b89dc8f5b9", size = 8922467, upload-time = "2025-12-10T07:08:47.408Z" }, + { url = "https://files.pythonhosted.org/packages/35/4d/748c9e2872637a57981a04adc038dacaa16ba8ca887b23e34953f0b3f742/scikit_learn-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:00d6f1d66fbcf4eba6e356e1420d33cc06c70a45bb1363cd6f6a8e4ebbbdece2", size = 8774395, upload-time = "2025-12-10T07:08:49.337Z" }, + { url = "https://files.pythonhosted.org/packages/60/22/d7b2ebe4704a5e50790ba089d5c2ae308ab6bb852719e6c3bd4f04c3a363/scikit_learn-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:f28dd15c6bb0b66ba09728cf09fd8736c304be29409bd8445a080c1280619e8c", size = 8002647, upload-time = "2025-12-10T07:08:51.601Z" }, +] + +[[package]] +name = "scipy" +version = "1.17.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7a/97/5a3609c4f8d58b039179648e62dd220f89864f56f7357f5d4f45c29eb2cc/scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0", size = 30573822, upload-time = "2026-02-23T00:26:24.851Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/75/b4ce781849931fef6fd529afa6b63711d5a733065722d0c3e2724af9e40a/scipy-1.17.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:1f95b894f13729334fb990162e911c9e5dc1ab390c58aa6cbecb389c5b5e28ec", size = 31613675, upload-time = "2026-02-23T00:16:00.13Z" }, + { url = "https://files.pythonhosted.org/packages/f7/58/bccc2861b305abdd1b8663d6130c0b3d7cc22e8d86663edbc8401bfd40d4/scipy-1.17.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:e18f12c6b0bc5a592ed23d3f7b891f68fd7f8241d69b7883769eb5d5dfb52696", size = 28162057, upload-time = "2026-02-23T00:16:09.456Z" }, + { url = "https://files.pythonhosted.org/packages/6d/ee/18146b7757ed4976276b9c9819108adbc73c5aad636e5353e20746b73069/scipy-1.17.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a3472cfbca0a54177d0faa68f697d8ba4c80bbdc19908c3465556d9f7efce9ee", size = 20334032, upload-time = "2026-02-23T00:16:17.358Z" }, + { url = "https://files.pythonhosted.org/packages/ec/e6/cef1cf3557f0c54954198554a10016b6a03b2ec9e22a4e1df734936bd99c/scipy-1.17.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:766e0dc5a616d026a3a1cffa379af959671729083882f50307e18175797b3dfd", size = 22709533, upload-time = "2026-02-23T00:16:25.791Z" }, + { url = "https://files.pythonhosted.org/packages/4d/60/8804678875fc59362b0fb759ab3ecce1f09c10a735680318ac30da8cd76b/scipy-1.17.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:744b2bf3640d907b79f3fd7874efe432d1cf171ee721243e350f55234b4cec4c", size = 33062057, upload-time = "2026-02-23T00:16:36.931Z" }, + { url = "https://files.pythonhosted.org/packages/09/7d/af933f0f6e0767995b4e2d705a0665e454d1c19402aa7e895de3951ebb04/scipy-1.17.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43af8d1f3bea642559019edfe64e9b11192a8978efbd1539d7bc2aaa23d92de4", size = 35349300, upload-time = "2026-02-23T00:16:49.108Z" }, + { url = "https://files.pythonhosted.org/packages/b4/3d/7ccbbdcbb54c8fdc20d3b6930137c782a163fa626f0aef920349873421ba/scipy-1.17.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd96a1898c0a47be4520327e01f874acfd61fb48a9420f8aa9f6483412ffa444", size = 35127333, upload-time = "2026-02-23T00:17:01.293Z" }, + { url = "https://files.pythonhosted.org/packages/e8/19/f926cb11c42b15ba08e3a71e376d816ac08614f769b4f47e06c3580c836a/scipy-1.17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4eb6c25dd62ee8d5edf68a8e1c171dd71c292fdae95d8aeb3dd7d7de4c364082", size = 37741314, upload-time = "2026-02-23T00:17:12.576Z" }, + { url = "https://files.pythonhosted.org/packages/95/da/0d1df507cf574b3f224ccc3d45244c9a1d732c81dcb26b1e8a766ae271a8/scipy-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:d30e57c72013c2a4fe441c2fcb8e77b14e152ad48b5464858e07e2ad9fbfceff", size = 36607512, upload-time = "2026-02-23T00:17:23.424Z" }, + { url = "https://files.pythonhosted.org/packages/68/7f/bdd79ceaad24b671543ffe0ef61ed8e659440eb683b66f033454dcee90eb/scipy-1.17.1-cp311-cp311-win_arm64.whl", hash = "sha256:9ecb4efb1cd6e8c4afea0daa91a87fbddbce1b99d2895d151596716c0b2e859d", size = 24599248, upload-time = "2026-02-23T00:17:34.561Z" }, + { url = "https://files.pythonhosted.org/packages/35/48/b992b488d6f299dbe3f11a20b24d3dda3d46f1a635ede1c46b5b17a7b163/scipy-1.17.1-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:35c3a56d2ef83efc372eaec584314bd0ef2e2f0d2adb21c55e6ad5b344c0dcb8", size = 31610954, upload-time = "2026-02-23T00:17:49.855Z" }, + { url = "https://files.pythonhosted.org/packages/b2/02/cf107b01494c19dc100f1d0b7ac3cc08666e96ba2d64db7626066cee895e/scipy-1.17.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:fcb310ddb270a06114bb64bbe53c94926b943f5b7f0842194d585c65eb4edd76", size = 28172662, upload-time = "2026-02-23T00:18:01.64Z" }, + { url = "https://files.pythonhosted.org/packages/cf/a9/599c28631bad314d219cf9ffd40e985b24d603fc8a2f4ccc5ae8419a535b/scipy-1.17.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:cc90d2e9c7e5c7f1a482c9875007c095c3194b1cfedca3c2f3291cdc2bc7c086", size = 20344366, upload-time = "2026-02-23T00:18:12.015Z" }, + { url = "https://files.pythonhosted.org/packages/35/f5/906eda513271c8deb5af284e5ef0206d17a96239af79f9fa0aebfe0e36b4/scipy-1.17.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:c80be5ede8f3f8eded4eff73cc99a25c388ce98e555b17d31da05287015ffa5b", size = 22704017, upload-time = "2026-02-23T00:18:21.502Z" }, + { url = "https://files.pythonhosted.org/packages/da/34/16f10e3042d2f1d6b66e0428308ab52224b6a23049cb2f5c1756f713815f/scipy-1.17.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e19ebea31758fac5893a2ac360fedd00116cbb7628e650842a6691ba7ca28a21", size = 32927842, upload-time = "2026-02-23T00:18:35.367Z" }, + { url = "https://files.pythonhosted.org/packages/01/8e/1e35281b8ab6d5d72ebe9911edcdffa3f36b04ed9d51dec6dd140396e220/scipy-1.17.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:02ae3b274fde71c5e92ac4d54bc06c42d80e399fec704383dcd99b301df37458", size = 35235890, upload-time = "2026-02-23T00:18:49.188Z" }, + { url = "https://files.pythonhosted.org/packages/c5/5c/9d7f4c88bea6e0d5a4f1bc0506a53a00e9fcb198de372bfe4d3652cef482/scipy-1.17.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8a604bae87c6195d8b1045eddece0514d041604b14f2727bbc2b3020172045eb", size = 35003557, upload-time = "2026-02-23T00:18:54.74Z" }, + { url = "https://files.pythonhosted.org/packages/65/94/7698add8f276dbab7a9de9fb6b0e02fc13ee61d51c7c3f85ac28b65e1239/scipy-1.17.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f590cd684941912d10becc07325a3eeb77886fe981415660d9265c4c418d0bea", size = 37625856, upload-time = "2026-02-23T00:19:00.307Z" }, + { url = "https://files.pythonhosted.org/packages/a2/84/dc08d77fbf3d87d3ee27f6a0c6dcce1de5829a64f2eae85a0ecc1f0daa73/scipy-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:41b71f4a3a4cab9d366cd9065b288efc4d4f3c0b37a91a8e0947fb5bd7f31d87", size = 36549682, upload-time = "2026-02-23T00:19:07.67Z" }, + { url = "https://files.pythonhosted.org/packages/bc/98/fe9ae9ffb3b54b62559f52dedaebe204b408db8109a8c66fdd04869e6424/scipy-1.17.1-cp312-cp312-win_arm64.whl", hash = "sha256:f4115102802df98b2b0db3cce5cb9b92572633a1197c77b7553e5203f284a5b3", size = 24547340, upload-time = "2026-02-23T00:19:12.024Z" }, + { url = "https://files.pythonhosted.org/packages/76/27/07ee1b57b65e92645f219b37148a7e7928b82e2b5dbeccecb4dff7c64f0b/scipy-1.17.1-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:5e3c5c011904115f88a39308379c17f91546f77c1667cea98739fe0fccea804c", size = 31590199, upload-time = "2026-02-23T00:19:17.192Z" }, + { url = "https://files.pythonhosted.org/packages/ec/ae/db19f8ab842e9b724bf5dbb7db29302a91f1e55bc4d04b1025d6d605a2c5/scipy-1.17.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:6fac755ca3d2c3edcb22f479fceaa241704111414831ddd3bc6056e18516892f", size = 28154001, upload-time = "2026-02-23T00:19:22.241Z" }, + { url = "https://files.pythonhosted.org/packages/5b/58/3ce96251560107b381cbd6e8413c483bbb1228a6b919fa8652b0d4090e7f/scipy-1.17.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:7ff200bf9d24f2e4d5dc6ee8c3ac64d739d3a89e2326ba68aaf6c4a2b838fd7d", size = 20325719, upload-time = "2026-02-23T00:19:26.329Z" }, + { url = "https://files.pythonhosted.org/packages/b2/83/15087d945e0e4d48ce2377498abf5ad171ae013232ae31d06f336e64c999/scipy-1.17.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:4b400bdc6f79fa02a4d86640310dde87a21fba0c979efff5248908c6f15fad1b", size = 22683595, upload-time = "2026-02-23T00:19:30.304Z" }, + { url = "https://files.pythonhosted.org/packages/b4/e0/e58fbde4a1a594c8be8114eb4aac1a55bcd6587047efc18a61eb1f5c0d30/scipy-1.17.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b64ca7d4aee0102a97f3ba22124052b4bd2152522355073580bf4845e2550b6", size = 32896429, upload-time = "2026-02-23T00:19:35.536Z" }, + { url = "https://files.pythonhosted.org/packages/f5/5f/f17563f28ff03c7b6799c50d01d5d856a1d55f2676f537ca8d28c7f627cd/scipy-1.17.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:581b2264fc0aa555f3f435a5944da7504ea3a065d7029ad60e7c3d1ae09c5464", size = 35203952, upload-time = "2026-02-23T00:19:42.259Z" }, + { url = "https://files.pythonhosted.org/packages/8d/a5/9afd17de24f657fdfe4df9a3f1ea049b39aef7c06000c13db1530d81ccca/scipy-1.17.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:beeda3d4ae615106d7094f7e7cef6218392e4465cc95d25f900bebabfded0950", size = 34979063, upload-time = "2026-02-23T00:19:47.547Z" }, + { url = "https://files.pythonhosted.org/packages/8b/13/88b1d2384b424bf7c924f2038c1c409f8d88bb2a8d49d097861dd64a57b2/scipy-1.17.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6609bc224e9568f65064cfa72edc0f24ee6655b47575954ec6339534b2798369", size = 37598449, upload-time = "2026-02-23T00:19:53.238Z" }, + { url = "https://files.pythonhosted.org/packages/35/e5/d6d0e51fc888f692a35134336866341c08655d92614f492c6860dc45bb2c/scipy-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:37425bc9175607b0268f493d79a292c39f9d001a357bebb6b88fdfaff13f6448", size = 36510943, upload-time = "2026-02-23T00:20:50.89Z" }, + { url = "https://files.pythonhosted.org/packages/2a/fd/3be73c564e2a01e690e19cc618811540ba5354c67c8680dce3281123fb79/scipy-1.17.1-cp313-cp313-win_arm64.whl", hash = "sha256:5cf36e801231b6a2059bf354720274b7558746f3b1a4efb43fcf557ccd484a87", size = 24545621, upload-time = "2026-02-23T00:20:55.871Z" }, + { url = "https://files.pythonhosted.org/packages/6f/6b/17787db8b8114933a66f9dcc479a8272e4b4da75fe03b0c282f7b0ade8cd/scipy-1.17.1-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:d59c30000a16d8edc7e64152e30220bfbd724c9bbb08368c054e24c651314f0a", size = 31936708, upload-time = "2026-02-23T00:19:58.694Z" }, + { url = "https://files.pythonhosted.org/packages/38/2e/524405c2b6392765ab1e2b722a41d5da33dc5c7b7278184a8ad29b6cb206/scipy-1.17.1-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:010f4333c96c9bb1a4516269e33cb5917b08ef2166d5556ca2fd9f082a9e6ea0", size = 28570135, upload-time = "2026-02-23T00:20:03.934Z" }, + { url = "https://files.pythonhosted.org/packages/fd/c3/5bd7199f4ea8556c0c8e39f04ccb014ac37d1468e6cfa6a95c6b3562b76e/scipy-1.17.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:2ceb2d3e01c5f1d83c4189737a42d9cb2fc38a6eeed225e7515eef71ad301dce", size = 20741977, upload-time = "2026-02-23T00:20:07.935Z" }, + { url = "https://files.pythonhosted.org/packages/d9/b8/8ccd9b766ad14c78386599708eb745f6b44f08400a5fd0ade7cf89b6fc93/scipy-1.17.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:844e165636711ef41f80b4103ed234181646b98a53c8f05da12ca5ca289134f6", size = 23029601, upload-time = "2026-02-23T00:20:12.161Z" }, + { url = "https://files.pythonhosted.org/packages/6d/a0/3cb6f4d2fb3e17428ad2880333cac878909ad1a89f678527b5328b93c1d4/scipy-1.17.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:158dd96d2207e21c966063e1635b1063cd7787b627b6f07305315dd73d9c679e", size = 33019667, upload-time = "2026-02-23T00:20:17.208Z" }, + { url = "https://files.pythonhosted.org/packages/f3/c3/2d834a5ac7bf3a0c806ad1508efc02dda3c8c61472a56132d7894c312dea/scipy-1.17.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:74cbb80d93260fe2ffa334efa24cb8f2f0f622a9b9febf8b483c0b865bfb3475", size = 35264159, upload-time = "2026-02-23T00:20:23.087Z" }, + { url = "https://files.pythonhosted.org/packages/4d/77/d3ed4becfdbd217c52062fafe35a72388d1bd82c2d0ba5ca19d6fcc93e11/scipy-1.17.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:dbc12c9f3d185f5c737d801da555fb74b3dcfa1a50b66a1a93e09190f41fab50", size = 35102771, upload-time = "2026-02-23T00:20:28.636Z" }, + { url = "https://files.pythonhosted.org/packages/bd/12/d19da97efde68ca1ee5538bb261d5d2c062f0c055575128f11a2730e3ac1/scipy-1.17.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:94055a11dfebe37c656e70317e1996dc197e1a15bbcc351bcdd4610e128fe1ca", size = 37665910, upload-time = "2026-02-23T00:20:34.743Z" }, + { url = "https://files.pythonhosted.org/packages/06/1c/1172a88d507a4baaf72c5a09bb6c018fe2ae0ab622e5830b703a46cc9e44/scipy-1.17.1-cp313-cp313t-win_amd64.whl", hash = "sha256:e30bdeaa5deed6bc27b4cc490823cd0347d7dae09119b8803ae576ea0ce52e4c", size = 36562980, upload-time = "2026-02-23T00:20:40.575Z" }, + { url = "https://files.pythonhosted.org/packages/70/b0/eb757336e5a76dfa7911f63252e3b7d1de00935d7705cf772db5b45ec238/scipy-1.17.1-cp313-cp313t-win_arm64.whl", hash = "sha256:a720477885a9d2411f94a93d16f9d89bad0f28ca23c3f8daa521e2dcc3f44d49", size = 24856543, upload-time = "2026-02-23T00:20:45.313Z" }, + { url = "https://files.pythonhosted.org/packages/cf/83/333afb452af6f0fd70414dc04f898647ee1423979ce02efa75c3b0f2c28e/scipy-1.17.1-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:a48a72c77a310327f6a3a920092fa2b8fd03d7deaa60f093038f22d98e096717", size = 31584510, upload-time = "2026-02-23T00:21:01.015Z" }, + { url = "https://files.pythonhosted.org/packages/ed/a6/d05a85fd51daeb2e4ea71d102f15b34fedca8e931af02594193ae4fd25f7/scipy-1.17.1-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:45abad819184f07240d8a696117a7aacd39787af9e0b719d00285549ed19a1e9", size = 28170131, upload-time = "2026-02-23T00:21:05.888Z" }, + { url = "https://files.pythonhosted.org/packages/db/7b/8624a203326675d7746a254083a187398090a179335b2e4a20e2ddc46e83/scipy-1.17.1-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:3fd1fcdab3ea951b610dc4cef356d416d5802991e7e32b5254828d342f7b7e0b", size = 20342032, upload-time = "2026-02-23T00:21:09.904Z" }, + { url = "https://files.pythonhosted.org/packages/c9/35/2c342897c00775d688d8ff3987aced3426858fd89d5a0e26e020b660b301/scipy-1.17.1-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:7bdf2da170b67fdf10bca777614b1c7d96ae3ca5794fd9587dce41eb2966e866", size = 22678766, upload-time = "2026-02-23T00:21:14.313Z" }, + { url = "https://files.pythonhosted.org/packages/ef/f2/7cdb8eb308a1a6ae1e19f945913c82c23c0c442a462a46480ce487fdc0ac/scipy-1.17.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:adb2642e060a6549c343603a3851ba76ef0b74cc8c079a9a58121c7ec9fe2350", size = 32957007, upload-time = "2026-02-23T00:21:19.663Z" }, + { url = "https://files.pythonhosted.org/packages/0b/2e/7eea398450457ecb54e18e9d10110993fa65561c4f3add5e8eccd2b9cd41/scipy-1.17.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eee2cfda04c00a857206a4330f0c5e3e56535494e30ca445eb19ec624ae75118", size = 35221333, upload-time = "2026-02-23T00:21:25.278Z" }, + { url = "https://files.pythonhosted.org/packages/d9/77/5b8509d03b77f093a0d52e606d3c4f79e8b06d1d38c441dacb1e26cacf46/scipy-1.17.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d2650c1fb97e184d12d8ba010493ee7b322864f7d3d00d3f9bb97d9c21de4068", size = 35042066, upload-time = "2026-02-23T00:21:31.358Z" }, + { url = "https://files.pythonhosted.org/packages/f9/df/18f80fb99df40b4070328d5ae5c596f2f00fffb50167e31439e932f29e7d/scipy-1.17.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:08b900519463543aa604a06bec02461558a6e1cef8fdbb8098f77a48a83c8118", size = 37612763, upload-time = "2026-02-23T00:21:37.247Z" }, + { url = "https://files.pythonhosted.org/packages/4b/39/f0e8ea762a764a9dc52aa7dabcfad51a354819de1f0d4652b6a1122424d6/scipy-1.17.1-cp314-cp314-win_amd64.whl", hash = "sha256:3877ac408e14da24a6196de0ddcace62092bfc12a83823e92e49e40747e52c19", size = 37290984, upload-time = "2026-02-23T00:22:35.023Z" }, + { url = "https://files.pythonhosted.org/packages/7c/56/fe201e3b0f93d1a8bcf75d3379affd228a63d7e2d80ab45467a74b494947/scipy-1.17.1-cp314-cp314-win_arm64.whl", hash = "sha256:f8885db0bc2bffa59d5c1b72fad7a6a92d3e80e7257f967dd81abb553a90d293", size = 25192877, upload-time = "2026-02-23T00:22:39.798Z" }, + { url = "https://files.pythonhosted.org/packages/96/ad/f8c414e121f82e02d76f310f16db9899c4fcde36710329502a6b2a3c0392/scipy-1.17.1-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:1cc682cea2ae55524432f3cdff9e9a3be743d52a7443d0cba9017c23c87ae2f6", size = 31949750, upload-time = "2026-02-23T00:21:42.289Z" }, + { url = "https://files.pythonhosted.org/packages/7c/b0/c741e8865d61b67c81e255f4f0a832846c064e426636cd7de84e74d209be/scipy-1.17.1-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:2040ad4d1795a0ae89bfc7e8429677f365d45aa9fd5e4587cf1ea737f927b4a1", size = 28585858, upload-time = "2026-02-23T00:21:47.706Z" }, + { url = "https://files.pythonhosted.org/packages/ed/1b/3985219c6177866628fa7c2595bfd23f193ceebbe472c98a08824b9466ff/scipy-1.17.1-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:131f5aaea57602008f9822e2115029b55d4b5f7c070287699fe45c661d051e39", size = 20757723, upload-time = "2026-02-23T00:21:52.039Z" }, + { url = "https://files.pythonhosted.org/packages/c0/19/2a04aa25050d656d6f7b9e7b685cc83d6957fb101665bfd9369ca6534563/scipy-1.17.1-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:9cdc1a2fcfd5c52cfb3045feb399f7b3ce822abdde3a193a6b9a60b3cb5854ca", size = 23043098, upload-time = "2026-02-23T00:21:56.185Z" }, + { url = "https://files.pythonhosted.org/packages/86/f1/3383beb9b5d0dbddd030335bf8a8b32d4317185efe495374f134d8be6cce/scipy-1.17.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e3dcd57ab780c741fde8dc68619de988b966db759a3c3152e8e9142c26295ad", size = 33030397, upload-time = "2026-02-23T00:22:01.404Z" }, + { url = "https://files.pythonhosted.org/packages/41/68/8f21e8a65a5a03f25a79165ec9d2b28c00e66dc80546cf5eb803aeeff35b/scipy-1.17.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a9956e4d4f4a301ebf6cde39850333a6b6110799d470dbbb1e25326ac447f52a", size = 35281163, upload-time = "2026-02-23T00:22:07.024Z" }, + { url = "https://files.pythonhosted.org/packages/84/8d/c8a5e19479554007a5632ed7529e665c315ae7492b4f946b0deb39870e39/scipy-1.17.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a4328d245944d09fd639771de275701ccadf5f781ba0ff092ad141e017eccda4", size = 35116291, upload-time = "2026-02-23T00:22:12.585Z" }, + { url = "https://files.pythonhosted.org/packages/52/52/e57eceff0e342a1f50e274264ed47497b59e6a4e3118808ee58ddda7b74a/scipy-1.17.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a77cbd07b940d326d39a1d1b37817e2ee4d79cb30e7338f3d0cddffae70fcaa2", size = 37682317, upload-time = "2026-02-23T00:22:18.513Z" }, + { url = "https://files.pythonhosted.org/packages/11/2f/b29eafe4a3fbc3d6de9662b36e028d5f039e72d345e05c250e121a230dd4/scipy-1.17.1-cp314-cp314t-win_amd64.whl", hash = "sha256:eb092099205ef62cd1782b006658db09e2fed75bffcae7cc0d44052d8aa0f484", size = 37345327, upload-time = "2026-02-23T00:22:24.442Z" }, + { url = "https://files.pythonhosted.org/packages/07/39/338d9219c4e87f3e708f18857ecd24d22a0c3094752393319553096b98af/scipy-1.17.1-cp314-cp314t-win_arm64.whl", hash = "sha256:200e1050faffacc162be6a486a984a0497866ec54149a01270adc8a59b7c7d21", size = 25489165, upload-time = "2026-02-23T00:22:29.563Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "sse-starlette" +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "starlette" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f7/2b/58abc2d1fd397e7dde08e947e05c884d8ef2f78d5e2588c17a12d42d6994/sse_starlette-3.4.4.tar.gz", hash = "sha256:07e0fa0460138baf25cdd5fb28683472c3995dc1642225191b3832d62526bcb0", size = 31819, upload-time = "2026-05-12T17:37:17.019Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/67/805710444ea8cc75fbf70b920ed431a560c4bf9c57f7d5a3117213189399/sse_starlette-3.4.4-py3-none-any.whl", hash = "sha256:3f4dd50d8aed2771a091f3a83000323fc3844541c16b4fe585ae2420cc6df973", size = 16514, upload-time = "2026-05-12T17:37:15.601Z" }, +] + +[[package]] +name = "stack-data" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asttokens" }, + { name = "executing" }, + { name = "pure-eval" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, +] + +[[package]] +name = "starlette" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/08/a3/84e821cc54b4ab50ae6dbc6ac3800a651b65ec35f045cc73785380654057/starlette-1.0.1.tar.gz", hash = "sha256:512399c5f1de7fac99c88572212ded9ddeddef2fb32afa82d724000e88b38f4f", size = 2659596, upload-time = "2026-05-21T21:58:58.433Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/e1/b2df4bc09a1e51ff664c1e17018a4274b42e5e9352e4a478ea540512dc88/starlette-1.0.1-py3-none-any.whl", hash = "sha256:7c0e69b2ee1c848bd54669d908500117a3ee13de603a21427e5c6fc1adf98dcd", size = 72802, upload-time = "2026-05-21T21:58:56.551Z" }, +] + +[[package]] +name = "tf-stocks-panel-backend" +version = "0.1.0" +source = { editable = "." } +dependencies = [ + { name = "apscheduler" }, + { name = "duckdb" }, + { name = "fastapi" }, + { name = "fastexcel" }, + { name = "httpx" }, + { name = "openai" }, + { name = "pandas" }, + { name = "polars" }, + { name = "pyarrow" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "python-dotenv" }, + { name = "python-multipart" }, + { name = "pyyaml" }, + { name = "sse-starlette" }, + { name = "tickflow", extra = ["all"] }, + { name = "uvicorn", extra = ["standard"] }, +] + +[package.optional-dependencies] +backtest = [ + { name = "vectorbt" }, +] +dev = [ + { name = "mypy" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "ruff" }, +] + +[package.metadata] +requires-dist = [ + { name = "apscheduler", specifier = ">=3.10" }, + { name = "duckdb", specifier = ">=1.0" }, + { name = "fastapi", specifier = ">=0.115" }, + { name = "fastexcel", specifier = ">=0.10" }, + { name = "httpx", specifier = ">=0.27" }, + { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.10" }, + { name = "openai", specifier = ">=1.40" }, + { name = "pandas", specifier = ">=2.2" }, + { name = "polars", specifier = ">=1.0" }, + { name = "pyarrow", specifier = ">=16.0" }, + { name = "pydantic", specifier = ">=2.7" }, + { name = "pydantic-settings", specifier = ">=2.4" }, + { name = "pytest", marker = "extra == 'dev'", specifier = ">=8.0" }, + { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.23" }, + { name = "python-dotenv", specifier = ">=1.0" }, + { name = "python-multipart", specifier = ">=0.0.6" }, + { name = "pyyaml", specifier = ">=6.0" }, + { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.5" }, + { name = "sse-starlette", specifier = ">=2.0" }, + { name = "tickflow", extras = ["all"], specifier = ">=0.1.21" }, + { name = "uvicorn", extras = ["standard"], specifier = ">=0.30" }, + { name = "vectorbt", marker = "extra == 'backtest'", specifier = ">=0.26" }, +] +provides-extras = ["backtest", "dev"] + +[[package]] +name = "threadpoolctl" +version = "3.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274, upload-time = "2025-03-13T13:49:23.031Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638, upload-time = "2025-03-13T13:49:21.846Z" }, +] + +[[package]] +name = "tickflow" +version = "0.1.21" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "httpx" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0a/80/b808d04f52171abaa7db8f6f9a69fd3e4afe3ca569f0d99964b242d2e70f/tickflow-0.1.21.tar.gz", hash = "sha256:17fcff4fa3d38805923d92e4861c0bb592a89c6e8a08187533fad2853dc50364", size = 37106, upload-time = "2026-04-29T10:15:29.949Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/53/57b629bcee5d9870a034a321c21325535612b9d69228612302e8facdcea7/tickflow-0.1.21-py3-none-any.whl", hash = "sha256:eba424d341b6ed7ba0c2ccd13e18e6d535513349b31ed9adcc5dd02c599980a4", size = 42731, upload-time = "2026-04-29T10:15:28.547Z" }, +] + +[package.optional-dependencies] +all = [ + { name = "pandas" }, + { name = "tqdm" }, + { name = "websockets" }, +] + +[[package]] +name = "tqdm" +version = "4.67.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/09/a9/6ba95a270c6f1fbcd8dac228323f2777d886cb206987444e4bce66338dd4/tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb", size = 169598, upload-time = "2026-02-03T17:35:53.048Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf", size = 78374, upload-time = "2026-02-03T17:35:50.982Z" }, +] + +[[package]] +name = "traitlets" +version = "5.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/22/40f55b26baeab80c2d7b3f1db0682f8954e4617fee7d90ce634022ef05c6/traitlets-5.15.0.tar.gz", hash = "sha256:4fead733f81cf1c4c938e06f8ca4633896833c9d89eff878159457f4d4392971", size = 163197, upload-time = "2026-05-06T08:05:58.016Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/98/a9937a969d018a23badfea0b381f66783649d48e0ea6c41923265c3cbeb3/traitlets-5.15.0-py3-none-any.whl", hash = "sha256:fb36a18867a6803deab09f3c5e0fa81bb7b26a5c9e82501c9933f759166eff40", size = 85877, upload-time = "2026-05-06T08:05:55.853Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, +] + +[[package]] +name = "tzdata" +version = "2026.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/19/1b9b0e29f30c6d35cb345486df41110984ea67ae69dddbc0e8a100999493/tzdata-2026.2.tar.gz", hash = "sha256:9173fde7d80d9018e02a662e168e5a2d04f87c41ea174b139fbef642eda62d10", size = 198254, upload-time = "2026-04-24T15:22:08.651Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl", hash = "sha256:bbe9af844f658da81a5f95019480da3a89415801f6cc966806612cc7169bffe7", size = 349321, upload-time = "2026-04-24T15:22:05.876Z" }, +] + +[[package]] +name = "tzlocal" +version = "5.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8b/2e/c14812d3d4d9cd1773c6be938f89e5735a1f11a9f184ac3639b93cef35d5/tzlocal-5.3.1.tar.gz", hash = "sha256:cceffc7edecefea1f595541dbd6e990cb1ea3d19bf01b2809f362a03dd7921fd", size = 30761, upload-time = "2025-03-05T21:17:41.549Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/14/e2a54fabd4f08cd7af1c07030603c3356b74da07f7cc056e600436edfa17/tzlocal-5.3.1-py3-none-any.whl", hash = "sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d", size = 18026, upload-time = "2025-03-05T21:17:39.857Z" }, +] + +[[package]] +name = "urllib3" +version = "2.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, +] + +[[package]] +name = "uvicorn" +version = "0.47.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f6/b1/8e7077a8641086aea449e1b5752a570f1b5906c64e0a33cd6d93b63a066b/uvicorn-0.47.0.tar.gz", hash = "sha256:7c9a0ea1a9414106bbab7324609c162d8fa0cdcdcb703060987269d77c7bb533", size = 90582, upload-time = "2026-05-14T18:16:54.455Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/15/41/ac2dfdbc1f60c7af4f994c7a335cfa7040c01642b605d65f611cecc2a1e4/uvicorn-0.47.0-py3-none-any.whl", hash = "sha256:2c5715bc12d1892d84752049f400cd1c3cb018514967fdfeb97640443a6a9432", size = 71301, upload-time = "2026-05-14T18:16:51.762Z" }, +] + +[package.optional-dependencies] +standard = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "httptools" }, + { name = "python-dotenv" }, + { name = "pyyaml" }, + { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, + { name = "watchfiles" }, + { name = "websockets" }, +] + +[[package]] +name = "uvloop" +version = "0.22.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250, upload-time = "2025-10-16T22:17:19.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/d5/69900f7883235562f1f50d8184bb7dd84a2fb61e9ec63f3782546fdbd057/uvloop-0.22.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c60ebcd36f7b240b30788554b6f0782454826a0ed765d8430652621b5de674b9", size = 1352420, upload-time = "2025-10-16T22:16:21.187Z" }, + { url = "https://files.pythonhosted.org/packages/a8/73/c4e271b3bce59724e291465cc936c37758886a4868787da0278b3b56b905/uvloop-0.22.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b7f102bf3cb1995cfeaee9321105e8f5da76fdb104cdad8986f85461a1b7b77", size = 748677, upload-time = "2025-10-16T22:16:22.558Z" }, + { url = "https://files.pythonhosted.org/packages/86/94/9fb7fad2f824d25f8ecac0d70b94d0d48107ad5ece03769a9c543444f78a/uvloop-0.22.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53c85520781d84a4b8b230e24a5af5b0778efdb39142b424990ff1ef7c48ba21", size = 3753819, upload-time = "2025-10-16T22:16:23.903Z" }, + { url = "https://files.pythonhosted.org/packages/74/4f/256aca690709e9b008b7108bc85fba619a2bc37c6d80743d18abad16ee09/uvloop-0.22.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:56a2d1fae65fd82197cb8c53c367310b3eabe1bbb9fb5a04d28e3e3520e4f702", size = 3804529, upload-time = "2025-10-16T22:16:25.246Z" }, + { url = "https://files.pythonhosted.org/packages/7f/74/03c05ae4737e871923d21a76fe28b6aad57f5c03b6e6bfcfa5ad616013e4/uvloop-0.22.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40631b049d5972c6755b06d0bfe8233b1bd9a8a6392d9d1c45c10b6f9e9b2733", size = 3621267, upload-time = "2025-10-16T22:16:26.819Z" }, + { url = "https://files.pythonhosted.org/packages/75/be/f8e590fe61d18b4a92070905497aec4c0e64ae1761498cad09023f3f4b3e/uvloop-0.22.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:535cc37b3a04f6cd2c1ef65fa1d370c9a35b6695df735fcff5427323f2cd5473", size = 3723105, upload-time = "2025-10-16T22:16:28.252Z" }, + { url = "https://files.pythonhosted.org/packages/3d/ff/7f72e8170be527b4977b033239a83a68d5c881cc4775fca255c677f7ac5d/uvloop-0.22.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:fe94b4564e865d968414598eea1a6de60adba0c040ba4ed05ac1300de402cd42", size = 1359936, upload-time = "2025-10-16T22:16:29.436Z" }, + { url = "https://files.pythonhosted.org/packages/c3/c6/e5d433f88fd54d81ef4be58b2b7b0cea13c442454a1db703a1eea0db1a59/uvloop-0.22.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:51eb9bd88391483410daad430813d982010f9c9c89512321f5b60e2cddbdddd6", size = 752769, upload-time = "2025-10-16T22:16:30.493Z" }, + { url = "https://files.pythonhosted.org/packages/24/68/a6ac446820273e71aa762fa21cdcc09861edd3536ff47c5cd3b7afb10eeb/uvloop-0.22.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:700e674a166ca5778255e0e1dc4e9d79ab2acc57b9171b79e65feba7184b3370", size = 4317413, upload-time = "2025-10-16T22:16:31.644Z" }, + { url = "https://files.pythonhosted.org/packages/5f/6f/e62b4dfc7ad6518e7eff2516f680d02a0f6eb62c0c212e152ca708a0085e/uvloop-0.22.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b5b1ac819a3f946d3b2ee07f09149578ae76066d70b44df3fa990add49a82e4", size = 4426307, upload-time = "2025-10-16T22:16:32.917Z" }, + { url = "https://files.pythonhosted.org/packages/90/60/97362554ac21e20e81bcef1150cb2a7e4ffdaf8ea1e5b2e8bf7a053caa18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e047cc068570bac9866237739607d1313b9253c3051ad84738cbb095be0537b2", size = 4131970, upload-time = "2025-10-16T22:16:34.015Z" }, + { url = "https://files.pythonhosted.org/packages/99/39/6b3f7d234ba3964c428a6e40006340f53ba37993f46ed6e111c6e9141d18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:512fec6815e2dd45161054592441ef76c830eddaad55c8aa30952e6fe1ed07c0", size = 4296343, upload-time = "2025-10-16T22:16:35.149Z" }, + { url = "https://files.pythonhosted.org/packages/89/8c/182a2a593195bfd39842ea68ebc084e20c850806117213f5a299dfc513d9/uvloop-0.22.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:561577354eb94200d75aca23fbde86ee11be36b00e52a4eaf8f50fb0c86b7705", size = 1358611, upload-time = "2025-10-16T22:16:36.833Z" }, + { url = "https://files.pythonhosted.org/packages/d2/14/e301ee96a6dc95224b6f1162cd3312f6d1217be3907b79173b06785f2fe7/uvloop-0.22.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cdf5192ab3e674ca26da2eada35b288d2fa49fdd0f357a19f0e7c4e7d5077c8", size = 751811, upload-time = "2025-10-16T22:16:38.275Z" }, + { url = "https://files.pythonhosted.org/packages/b7/02/654426ce265ac19e2980bfd9ea6590ca96a56f10c76e63801a2df01c0486/uvloop-0.22.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e2ea3d6190a2968f4a14a23019d3b16870dd2190cd69c8180f7c632d21de68d", size = 4288562, upload-time = "2025-10-16T22:16:39.375Z" }, + { url = "https://files.pythonhosted.org/packages/15/c0/0be24758891ef825f2065cd5db8741aaddabe3e248ee6acc5e8a80f04005/uvloop-0.22.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0530a5fbad9c9e4ee3f2b33b148c6a64d47bbad8000ea63704fa8260f4cf728e", size = 4366890, upload-time = "2025-10-16T22:16:40.547Z" }, + { url = "https://files.pythonhosted.org/packages/d2/53/8369e5219a5855869bcee5f4d317f6da0e2c669aecf0ef7d371e3d084449/uvloop-0.22.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bc5ef13bbc10b5335792360623cc378d52d7e62c2de64660616478c32cd0598e", size = 4119472, upload-time = "2025-10-16T22:16:41.694Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ba/d69adbe699b768f6b29a5eec7b47dd610bd17a69de51b251126a801369ea/uvloop-0.22.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1f38ec5e3f18c8a10ded09742f7fb8de0108796eb673f30ce7762ce1b8550cad", size = 4239051, upload-time = "2025-10-16T22:16:43.224Z" }, + { url = "https://files.pythonhosted.org/packages/90/cd/b62bdeaa429758aee8de8b00ac0dd26593a9de93d302bff3d21439e9791d/uvloop-0.22.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3879b88423ec7e97cd4eba2a443aa26ed4e59b45e6b76aabf13fe2f27023a142", size = 1362067, upload-time = "2025-10-16T22:16:44.503Z" }, + { url = "https://files.pythonhosted.org/packages/0d/f8/a132124dfda0777e489ca86732e85e69afcd1ff7686647000050ba670689/uvloop-0.22.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4baa86acedf1d62115c1dc6ad1e17134476688f08c6efd8a2ab076e815665c74", size = 752423, upload-time = "2025-10-16T22:16:45.968Z" }, + { url = "https://files.pythonhosted.org/packages/a3/94/94af78c156f88da4b3a733773ad5ba0b164393e357cc4bd0ab2e2677a7d6/uvloop-0.22.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:297c27d8003520596236bdb2335e6b3f649480bd09e00d1e3a99144b691d2a35", size = 4272437, upload-time = "2025-10-16T22:16:47.451Z" }, + { url = "https://files.pythonhosted.org/packages/b5/35/60249e9fd07b32c665192cec7af29e06c7cd96fa1d08b84f012a56a0b38e/uvloop-0.22.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c1955d5a1dd43198244d47664a5858082a3239766a839b2102a269aaff7a4e25", size = 4292101, upload-time = "2025-10-16T22:16:49.318Z" }, + { url = "https://files.pythonhosted.org/packages/02/62/67d382dfcb25d0a98ce73c11ed1a6fba5037a1a1d533dcbb7cab033a2636/uvloop-0.22.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b31dc2fccbd42adc73bc4e7cdbae4fc5086cf378979e53ca5d0301838c5682c6", size = 4114158, upload-time = "2025-10-16T22:16:50.517Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/f1171b4a882a5d13c8b7576f348acfe6074d72eaf52cccef752f748d4a9f/uvloop-0.22.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:93f617675b2d03af4e72a5333ef89450dfaa5321303ede6e67ba9c9d26878079", size = 4177360, upload-time = "2025-10-16T22:16:52.646Z" }, + { url = "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:37554f70528f60cad66945b885eb01f1bb514f132d92b6eeed1c90fd54ed6289", size = 1454790, upload-time = "2025-10-16T22:16:54.355Z" }, + { url = "https://files.pythonhosted.org/packages/d4/31/0bb232318dd838cad3fa8fb0c68c8b40e1145b32025581975e18b11fab40/uvloop-0.22.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:b76324e2dc033a0b2f435f33eb88ff9913c156ef78e153fb210e03c13da746b3", size = 796783, upload-time = "2025-10-16T22:16:55.906Z" }, + { url = "https://files.pythonhosted.org/packages/42/38/c9b09f3271a7a723a5de69f8e237ab8e7803183131bc57c890db0b6bb872/uvloop-0.22.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:badb4d8e58ee08dad957002027830d5c3b06aea446a6a3744483c2b3b745345c", size = 4647548, upload-time = "2025-10-16T22:16:57.008Z" }, + { url = "https://files.pythonhosted.org/packages/c1/37/945b4ca0ac27e3dc4952642d4c900edd030b3da6c9634875af6e13ae80e5/uvloop-0.22.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b91328c72635f6f9e0282e4a57da7470c7350ab1c9f48546c0f2866205349d21", size = 4467065, upload-time = "2025-10-16T22:16:58.206Z" }, + { url = "https://files.pythonhosted.org/packages/97/cc/48d232f33d60e2e2e0b42f4e73455b146b76ebe216487e862700457fbf3c/uvloop-0.22.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:daf620c2995d193449393d6c62131b3fbd40a63bf7b307a1527856ace637fe88", size = 4328384, upload-time = "2025-10-16T22:16:59.36Z" }, + { url = "https://files.pythonhosted.org/packages/e4/16/c1fd27e9549f3c4baf1dc9c20c456cd2f822dbf8de9f463824b0c0357e06/uvloop-0.22.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6cde23eeda1a25c75b2e07d39970f3374105d5eafbaab2a4482be82f272d5a5e", size = 4296730, upload-time = "2025-10-16T22:17:00.744Z" }, +] + +[[package]] +name = "vectorbt" +version = "0.28.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "dateparser" }, + { name = "dill" }, + { name = "imageio" }, + { name = "ipywidgets" }, + { name = "matplotlib" }, + { name = "mypy-extensions" }, + { name = "numba" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "plotly" }, + { name = "pytz" }, + { name = "requests" }, + { name = "schedule" }, + { name = "scikit-learn" }, + { name = "scipy" }, + { name = "tqdm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c5/a7/15e6af76aa8dafd18c7fae2068de889a385fd13eb804aacb8e0310765f1b/vectorbt-0.28.2.tar.gz", hash = "sha256:e1a5b7a11c0e2b5b271f18093cb7d1ea075d94d711388c0f423355e83c63c104", size = 487377, upload-time = "2025-12-12T16:18:12.818Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/b9/250f7a1d033618bd0e43ae40bc180aa88895c907876ca39e219a45caecca/vectorbt-0.28.2-py3-none-any.whl", hash = "sha256:93e5fb20d2ff072b7fed78603b516eb64f967c9bf9420ce8ba28329af0410e7d", size = 527808, upload-time = "2025-12-12T16:18:10.624Z" }, +] + +[[package]] +name = "watchfiles" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cd/41/5e1a4bb12aac5f1493fa1bdc11154eca3b258ca4eba65d39c473fe19d8e9/watchfiles-1.2.0.tar.gz", hash = "sha256:c995fba777f1ea992f090f9236e9284cf7a5d1a0130dd5a3d82c598cacd76838", size = 108252, upload-time = "2026-05-18T04:32:04.251Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/3d/8024c801df84d1587740d0359e7fdd80afeae3d159011f3d5376dd82f18e/watchfiles-1.2.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:704fd259e332e01f9b9c178f4bce9e49027e5587cc2600eeeaf8e76e1c846201", size = 400242, upload-time = "2026-05-18T04:31:19.014Z" }, + { url = "https://files.pythonhosted.org/packages/87/5b/f4dfd45323e949984a3a7f9dc31d1cbb049921e7d98253488dda72ccdaa9/watchfiles-1.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6543cf55d170003296d185c0af981f3e1311564907e1f4e08671fc7693a890a5", size = 394562, upload-time = "2026-05-18T04:30:08.46Z" }, + { url = "https://files.pythonhosted.org/packages/98/d8/19483ef075d601c409bce8bcbb5c0f81a10876fff870400568f08ce484a1/watchfiles-1.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89d8c2394a065ca86f5d2910ff263ae67c127e1376ccc4f9fc35c71db879f80a", size = 456611, upload-time = "2026-05-18T04:30:45.723Z" }, + { url = "https://files.pythonhosted.org/packages/b1/6a/cc81fbe7ee42f2f22e661a6e12def7807e01b14b2f39e0ff83fd373fd307/watchfiles-1.2.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:772b80df316480d894a0e3165fdd19cf77f5d17f9a787f94029465ad0e3529d1", size = 461379, upload-time = "2026-05-18T04:31:29.292Z" }, + { url = "https://files.pythonhosted.org/packages/b1/57/7e669002082c0a0f4fb5113bb70125f7110124b846b0a11bc5ae8e90eac1/watchfiles-1.2.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d158cd89df6053823533e06fb1d73c549133bff5f0396170c0e53d9559340717", size = 493556, upload-time = "2026-05-18T04:30:05.44Z" }, + { url = "https://files.pythonhosted.org/packages/45/7d/f60a2b19807b21fe8281f3a8da4f59eef0d5f96825ac4680ba2d4f2ebf91/watchfiles-1.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d516b3283a758e087841aedb8031549fb41ced08f3db10aa6d2bf32dc042525b", size = 575255, upload-time = "2026-05-18T04:30:40.568Z" }, + { url = "https://files.pythonhosted.org/packages/bd/49/77f5b5e6efbcd57482f74948ebb1b97e5c0046d6b61475042d830c84b3ff/watchfiles-1.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:53b2290c92e0506d102cd448fbc610d87079553f86caa39d67440856a8b8bba5", size = 467052, upload-time = "2026-05-18T04:31:17.942Z" }, + { url = "https://files.pythonhosted.org/packages/ee/5a/73e2959af1b97fd5d556f9a8bdba017be23ceeef731869d5eaa0a753d5a3/watchfiles-1.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a711b51aec4370d0dcda5b6c09463206f133a5759341d7744b953a7b62e1100e", size = 456858, upload-time = "2026-05-18T04:30:30.182Z" }, + { url = "https://files.pythonhosted.org/packages/50/57/1bc8c27fad7e6c19bddee15d276dbb6ab72480ec01c127afff1673aee417/watchfiles-1.2.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:e2ca07fa7d89195ec0865d3d285666286740bfa83d83e5cee204043a31ecc165", size = 467579, upload-time = "2026-05-18T04:32:15.897Z" }, + { url = "https://files.pythonhosted.org/packages/09/6c/3c2e44edba3553c5e3c3b8c8a2a6dee6b9e12ae2cf4bd2378bebf9dc3038/watchfiles-1.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e0618518f282c4ebff60f5e5b1247b6d91bb8b9f4476947563a1e74acc66f3c6", size = 633253, upload-time = "2026-05-18T04:31:37.123Z" }, + { url = "https://files.pythonhosted.org/packages/30/c2/d8c84a882ab39bbefcc4915ab3e91830b7a7e990c5570b0b69075aba3faf/watchfiles-1.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0d191c054d0715c3c95c99df9b8dbf6fd096d8c1e021e8f212e1bd8bc444ccb5", size = 660713, upload-time = "2026-05-18T04:31:24.62Z" }, + { url = "https://files.pythonhosted.org/packages/a9/07/f97736a5fc605364fe67b25e9fa4a6965dfd4840d50c406ada507e9d735f/watchfiles-1.2.0-cp311-cp311-win32.whl", hash = "sha256:9342472aff9b093c5acd4f6d8f70ae0937964ab56542502bcf5579782da69ae8", size = 277222, upload-time = "2026-05-18T04:31:21.131Z" }, + { url = "https://files.pythonhosted.org/packages/cf/99/2b04981977fc2608afd60360d928c6aecf6b950292ca221d98f4005f6694/watchfiles-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:dbd6c97045dad81227c8d040173da044c1de08de64a5ea8b555da4aee1d5fa22", size = 290274, upload-time = "2026-05-18T04:31:45.966Z" }, + { url = "https://files.pythonhosted.org/packages/3c/74/f7f58a7075ee9cf612b0cfcddb78b8cd8234f0742d6f0075cf0da2dde1c6/watchfiles-1.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:57a2d9fa4fb4c2ecae57b13dfff2c7ab53e21a2ba674fe9f05506680fcdcc0d7", size = 283460, upload-time = "2026-05-18T04:31:39.126Z" }, + { url = "https://files.pythonhosted.org/packages/b8/2f/e42c992d2afda3108ea1c02acecc991b9f31d05c14adc2a7cee9ee211fc4/watchfiles-1.2.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:bc13eb17538be00c874699dc0abe4ee2bc8d50bb1166a6b9e175ef3fd7eb8f26", size = 400115, upload-time = "2026-05-18T04:32:02.06Z" }, + { url = "https://files.pythonhosted.org/packages/5f/8f/6af2ea19065c91d8b0ea3516fdfc8c0d349f407e8e9fbf4e5a17360de8ad/watchfiles-1.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2d95ddc1eb6914154253d239089900813f6a767e174b8e6a50e7fdacb7e4236c", size = 393659, upload-time = "2026-05-18T04:30:50.951Z" }, + { url = "https://files.pythonhosted.org/packages/13/01/b32a967c56fb3e3e5be3db52c3d3b87fa4513aa367d8ed1ad96d42952e5f/watchfiles-1.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f70d8b291ef6e88d19b1f297a6905ddb978888d9272b0d05e6f53309856bcfc", size = 453207, upload-time = "2026-05-18T04:31:04.231Z" }, + { url = "https://files.pythonhosted.org/packages/04/98/97557a812180338cb1abd32e1cffcc4588f59b5f23e0cb006b2ba95ba64a/watchfiles-1.2.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:56d8641cf834c2836922899105bd3ce3d0dfc69291d52edf0b4d0436829b34c0", size = 459273, upload-time = "2026-05-18T04:31:50.377Z" }, + { url = "https://files.pythonhosted.org/packages/e8/a8/b4b08dcb7653b8087c6586f7ce649505900e866bbcfe40dc9587af02e686/watchfiles-1.2.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2581a94056e55d7d0a31a823ea92bf73749c489ca2285bfdc0fbe6b2bb49d50c", size = 489927, upload-time = "2026-05-18T04:31:42.485Z" }, + { url = "https://files.pythonhosted.org/packages/50/94/3dceea03545d2e5ddfd839f0ddd5e1cecbf1697b5a428d5ba11cef6af95d/watchfiles-1.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:41bc1199f7523b3f82843c88cbb979180c949caef0342cf90968f178e5d49b01", size = 570476, upload-time = "2026-05-18T04:31:03.071Z" }, + { url = "https://files.pythonhosted.org/packages/cc/f2/d39a5450c3532092b91f81d274360e613c2371bc874a89c7a1a3c5e8d138/watchfiles-1.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7571e4464cb6e434958f867f7f730b8ab0b75e3f8e5eac0499168486ab3c33a8", size = 465650, upload-time = "2026-05-18T04:30:12.701Z" }, + { url = "https://files.pythonhosted.org/packages/22/24/ed72f68cbc1333ca9b9f2200aa048bb6658ae41709bc1caad4310f4bdffd/watchfiles-1.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e53a384f76b631c3ae5334ce6a52f0baa3a911eb94a4eac7f160079868b716d5", size = 456398, upload-time = "2026-05-18T04:30:13.784Z" }, + { url = "https://files.pythonhosted.org/packages/0d/64/982ef4a4e5bab5b6e5b6becc8cd5e732f6130a78b855f0abec6439a9a135/watchfiles-1.2.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:d20029a60a71a052a24c4db7673bc4de39ab89adbaccbfb5d67987c5d73f424d", size = 465140, upload-time = "2026-05-18T04:31:52.111Z" }, + { url = "https://files.pythonhosted.org/packages/a0/0c/95282abf4ed680b6096010bcfc30c5fa7a041fc5aa5a2ad17a2cc6c75bba/watchfiles-1.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:2cb93af48550faf1cea04c303107c8b75833de7013e57ce27d3b8d21d8d0f58c", size = 630259, upload-time = "2026-05-18T04:31:25.676Z" }, + { url = "https://files.pythonhosted.org/packages/30/45/607c1de1530c4bdcf2cf1d1ecc2505ddba5d96bd43ba9f2b0e79876f850f/watchfiles-1.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2995c176de7692b86a2e4c58d9ec718f753150a979cb4a754e2b4ffa38e70906", size = 659859, upload-time = "2026-05-18T04:30:24.333Z" }, + { url = "https://files.pythonhosted.org/packages/fa/08/d9e2e0f9e8e6791d33aefc694ad7eefa7f901f63caff84a81ded38692f9c/watchfiles-1.2.0-cp312-cp312-win32.whl", hash = "sha256:7a2cffd17d27d2ecbb310c2b1d8174f222a5495b1a721894afa88ec11e25b898", size = 275480, upload-time = "2026-05-18T04:30:31.307Z" }, + { url = "https://files.pythonhosted.org/packages/1c/e6/9d42569c0102645cc8cea5d8c7d8a1e9d4ada2cb7f05f75e554b8aa2202a/watchfiles-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:f155b3a1b2a5fc89cdc70d47ee5d54e3b75e88efa34982028a35daef9ba00379", size = 288718, upload-time = "2026-05-18T04:32:10.745Z" }, + { url = "https://files.pythonhosted.org/packages/0a/26/88e0dc6ee3898169d7fa22bb6a69cabf2502d2ee25cb8c876d1262d204f8/watchfiles-1.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:8fa585ede612ee9f9e91b18bebf9ba11b9ae29a4e3a0d0cf6fca3e382133f0d5", size = 281026, upload-time = "2026-05-18T04:30:22.23Z" }, + { url = "https://files.pythonhosted.org/packages/d1/4d/70a7feced9f87e2ff26dba42667290f41694fc64646c67261fbb8cab5d5c/watchfiles-1.2.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:01ea8d66f0693b9b60a6541c8d10263091ca9a9060d242f3c1f3143f9aad2c98", size = 399730, upload-time = "2026-05-18T04:31:38.162Z" }, + { url = "https://files.pythonhosted.org/packages/31/3a/0da302f2307aee316922806ebd5726c542cbd787c938271cf14a074c7daf/watchfiles-1.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7ba0480b9a74af058f43b337e937a451e109295c420916d68ad24e3dc02f5e44", size = 392842, upload-time = "2026-05-18T04:30:27.051Z" }, + { url = "https://files.pythonhosted.org/packages/db/ef/d5bdb705c224dbc256aa0c1ec47bf4e61ec52558f2afb44a71a1fe4d7015/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f34e26a19f91f710c08e0183429f0d1d15df734e6bc78c31e77b9ea9c433658", size = 452989, upload-time = "2026-05-18T04:31:11.945Z" }, + { url = "https://files.pythonhosted.org/packages/71/29/5495f2c1661949ef7a35e4d71111d129cfe7606414a26887a919d0a55406/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b4e77f6a55f858504069abd35d336a637555c09bca453dde1ee1e5ada8a6a1fb", size = 458978, upload-time = "2026-05-18T04:30:52.606Z" }, + { url = "https://files.pythonhosted.org/packages/d5/8c/7f9c07c433811c2fffd93e13fdfb7135de9aab5f2ae41be08960fa0047dc/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0cb4d80e212f116474a545c21c912b445f16bb0cef9e6a73a498164223e14e2f", size = 490248, upload-time = "2026-05-18T04:31:36.003Z" }, + { url = "https://files.pythonhosted.org/packages/3c/11/d93632febc52fbc21be90231bb7c17fd5387f46c9076fd40a5f9c2ae6910/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b974946a10af379d425e2eef5b62f5c6ebeaccf91d45eaad6f5b27ecd4f91aa0", size = 571847, upload-time = "2026-05-18T04:31:10.862Z" }, + { url = "https://files.pythonhosted.org/packages/55/b4/383173e73aabb07ad1d9c7aa859d95437ac46a6d6a1e11005facda0c9d19/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86bc13c25a8d1fcd70b51d0ce7c9b65e90de5666fcbfd3e34957cc73ee19aeb5", size = 465974, upload-time = "2026-05-18T04:30:17.006Z" }, + { url = "https://files.pythonhosted.org/packages/a7/6c/89b1a230a78f57c52dd8893adb1f92f94411721b6ec12596c56d98c74356/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca148d73dea36c9763aaa351e4d7a51780ec1584217c45276f4fe8239c768b71", size = 454782, upload-time = "2026-05-18T04:30:35.656Z" }, + { url = "https://files.pythonhosted.org/packages/24/62/1732118367cfff0a9fce3bf62ff4bfded09ef5df21d9d446b858b3f70a96/watchfiles-1.2.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:c525543d91961c6955b2636b308569e84a1d1c5f5f2932041ab9ef46422f43e3", size = 465182, upload-time = "2026-05-18T04:30:20.846Z" }, + { url = "https://files.pythonhosted.org/packages/28/96/716f7e5f51339bf22963f3345f9f27d7f3b30e2eadc597e257c881dd3c53/watchfiles-1.2.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:a204794696ffb8f9b10fba6f7cb5216d42f3b2b71860ccac6b6e42f5f10973b0", size = 629841, upload-time = "2026-05-18T04:31:05.397Z" }, + { url = "https://files.pythonhosted.org/packages/4c/fe/c40783950fd771ccf66ab3ec2722d188a9af1c7f96c6e811f36e40c6e03f/watchfiles-1.2.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:10d86db20695afe7997ac9e1717637d6714a8d0220458c33f3d2061f54cec427", size = 658028, upload-time = "2026-05-18T04:31:48.22Z" }, + { url = "https://files.pythonhosted.org/packages/71/72/4508db1856d1d87fcbb3b63f4839bab1b5682cb0e8d224d122263c09654a/watchfiles-1.2.0-cp313-cp313-win32.whl", hash = "sha256:eb283ee99e21ad6443c8cdb06ac5b34b1308c329cbdf03fa02b445363714c799", size = 275183, upload-time = "2026-05-18T04:30:59.57Z" }, + { url = "https://files.pythonhosted.org/packages/f9/36/14b76ca57652e5cc5fd1c11f32a261292c08a0d19a00351013c2549cbfb2/watchfiles-1.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:a0f27f01bee51861392bb6b7c4fdb290b27d1eb194e9e28788d68102a0e898d9", size = 288059, upload-time = "2026-05-18T04:32:07.937Z" }, + { url = "https://files.pythonhosted.org/packages/1b/8d/0a85e395398d8d20fadfe5c5d32c726eee17a519e78fb356f2cf7531bffe/watchfiles-1.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:3651aa7058595e9cfb75d35dd5ada2bf9f48a5b8a0f3562821d3e210c507e077", size = 280186, upload-time = "2026-05-18T04:31:54.484Z" }, + { url = "https://files.pythonhosted.org/packages/37/68/36db056f1fdcc5f07302f56e631774d6835bcd6fa3ace402304621d5f9e5/watchfiles-1.2.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:faea288b6f0ab1902ef08f4ca6de005dccf856c4e0c4f21b8c5fce02d90a1b08", size = 399031, upload-time = "2026-05-18T04:30:44.576Z" }, + { url = "https://files.pythonhosted.org/packages/c1/64/01a9d6f66a82a5c101ce939274106cc72759d62427e153f01edd2b9f87c2/watchfiles-1.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:01859b11fd9fbca670f4d5da00fbac282cfea9bd67a2125d8b2833a3b5617ea9", size = 391205, upload-time = "2026-05-18T04:30:25.413Z" }, + { url = "https://files.pythonhosted.org/packages/84/2c/0a44fe058cb4bb7b8ede6b6670698bbb7c0400740e378d00022189b7b31d/watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fff610d7bb2256a317bb1e96f0d7862c7aa8076733ee5df0fd41bbe76a24a4f4", size = 451892, upload-time = "2026-05-18T04:32:14.005Z" }, + { url = "https://files.pythonhosted.org/packages/67/a1/351e0d56cd35e6488b5c8b4fb11a809a5bc923e8fe8fed9faf8920be0c89/watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b141a4891c995a039cd89e9a49e62df1dc8a559a5d1a6e4c7106d16c12777a55", size = 458867, upload-time = "2026-05-18T04:31:22.279Z" }, + { url = "https://files.pythonhosted.org/packages/d5/7d/9d09605187f1b838998624049fcf8bf47b73c1a3b76901fcac1782f62277/watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f22943b7770483f6ea0721c6b11d022947a98eb0acae14694de034f4d0d38925", size = 490217, upload-time = "2026-05-18T04:31:43.657Z" }, + { url = "https://files.pythonhosted.org/packages/60/5d/a17a16eccb182f04188cd308ec24b1a71a9b5c4e7098269cf35d9fa56d02/watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1bc6195825b7dcd217968bb1f801a60fd4c16e8eeab5bedc7fe917d7d5995ab4", size = 571458, upload-time = "2026-05-18T04:32:11.875Z" }, + { url = "https://files.pythonhosted.org/packages/d3/3d/4dd457062083ab1938e5dfd45032eb425cee2ac817287ca8ff4356183e5d/watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4a4b147f5dca2a5d325a06a832fb43f345751adfbc63204aec30e0d9ca965a2", size = 464707, upload-time = "2026-05-18T04:30:43.492Z" }, + { url = "https://files.pythonhosted.org/packages/c6/71/ea8c57b128f5383de74d0c7d2d9c57ad7c9a65a930c451bd25d524b295b7/watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4543579a9bdb0c9560039b4ffddbdb39545707659fbc430ce4c10f3f68d557f9", size = 454663, upload-time = "2026-05-18T04:30:16.061Z" }, + { url = "https://files.pythonhosted.org/packages/53/fd/2e812bf938406d7db351f0703ddd3fc6c061cf30d96153a77bc79a943a44/watchfiles-1.2.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:20aa0e708b920bde876a4aa82dc7dd6ebea228a63a67cda6632c2fc87b787efa", size = 463537, upload-time = "2026-05-18T04:31:44.9Z" }, + { url = "https://files.pythonhosted.org/packages/86/56/d17a7f1dd1bc3035f1072694a551301272f1739c2d8e319c927cb9e29b38/watchfiles-1.2.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:d413349d565dab74297f2a63e84a097936be69bf8f3b3801f27f380e32040f44", size = 629194, upload-time = "2026-05-18T04:31:14.141Z" }, + { url = "https://files.pythonhosted.org/packages/be/06/f1ff66bf5cae50aa4062779a0ecd0bbaf15e466195719074078947d9a17d/watchfiles-1.2.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:f28b2725eb8cce327b9b3ab02415c853011dc55c95832fe90de6bc56f5315f72", size = 656194, upload-time = "2026-05-18T04:31:47.14Z" }, + { url = "https://files.pythonhosted.org/packages/e7/54/a9c7ea9a82a4ac65e7004c0a03920b5cdd2f9c3b678757d9cd425aa51d53/watchfiles-1.2.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:b8c8358484d5fa12ef34f05b7f4168eaf1932f408725ff6d023c33ec17bd79d4", size = 400205, upload-time = "2026-05-18T04:32:05.153Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5d/c9ab3534374a4a67450696905d6ef16a04405448b8dc52bd752ae50423d4/watchfiles-1.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f04b092229ad2c50126dd3c922c8822e51e605993764a33058d4a791ab42281", size = 392508, upload-time = "2026-05-18T04:30:54.849Z" }, + { url = "https://files.pythonhosted.org/packages/26/ca/1ad30103535cf0cecd7b993e8d50edc5351b1820e38f2d22e3df58962feb/watchfiles-1.2.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a7ce236284f002a156f70add88efe5c70879cccbb658be0822c54b1306fc09d", size = 452448, upload-time = "2026-05-18T04:30:53.727Z" }, + { url = "https://files.pythonhosted.org/packages/37/a1/ceee2cdf2afbd715fa07758d39c9859513eae411b23196f7fd039e5feedd/watchfiles-1.2.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b9909cc2b48468b575eefa944919e1fe8a36c5849d5c7c168f80a8c1db69398e", size = 459605, upload-time = "2026-05-18T04:30:23.312Z" }, + { url = "https://files.pythonhosted.org/packages/e8/f6/421e30fd1cb3907a84ed92ab3f1983e37ba2dca015e9a894a048418417a2/watchfiles-1.2.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a37faaed405c67e28e6be45a1fa4f206ef5a2860f27c237db9fa30704c38242", size = 490757, upload-time = "2026-05-18T04:30:47.358Z" }, + { url = "https://files.pythonhosted.org/packages/41/b0/55ed1b97ed08be7bba6f9a541cac15f2a858e1d74d2b07b6da70a82aab00/watchfiles-1.2.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9649193aa27bd9ff2e80ff29bfaa93085496c7a3a377592823cc58b77ee88add", size = 568672, upload-time = "2026-05-18T04:30:38.915Z" }, + { url = "https://files.pythonhosted.org/packages/d1/cf/d8ae8a80dd7bafab395ea7681c10237311bbf34d37704a8c744e7cf31fc7/watchfiles-1.2.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e4ff8e37f99cf1da89e255e07c9c4b37c214038c4283707bdec308cb1b0ea1f", size = 464197, upload-time = "2026-05-18T04:30:09.914Z" }, + { url = "https://files.pythonhosted.org/packages/7c/8a/3076c496ca8dafe0e8cd03fcebdfc47be4b1174b4e5b24ff6e396e6b3af2/watchfiles-1.2.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:054dc20fd2e3132b4c3883b4a00d72fd6e1f56fdaf89fccd12e8057d74cd74d7", size = 453181, upload-time = "2026-05-18T04:30:14.829Z" }, + { url = "https://files.pythonhosted.org/packages/e5/10/9745e17c98e7b8a86454df0a3c7b5686bd650383f1e9f26e4ebcbd6cc0c0/watchfiles-1.2.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:e140ed30ebde76796b686e67c182cff10ea2fbab186fafd1560f74bb5a473a6e", size = 465109, upload-time = "2026-05-18T04:30:28.123Z" }, + { url = "https://files.pythonhosted.org/packages/8f/95/8ef4a95481d3e0cb52d62a06fa6e972e81424be2d9698b91a2fecca9904c/watchfiles-1.2.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:bb7e52ecf68ba46d22df23467b87cffeb2146908aa523ebfe803019618cfda06", size = 630653, upload-time = "2026-05-18T04:31:49.304Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e4/3b3bf36b0f829b50c6ebcb8d031583863c59f923d6a6af3d485e470d0fac/watchfiles-1.2.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:23282a321c8baf9b3a3c4afff673f9fe65eb7fdc2338d765ccad9d3d1916a5ba", size = 657838, upload-time = "2026-05-18T04:31:06.497Z" }, + { url = "https://files.pythonhosted.org/packages/21/b1/6cbbb50c1f3002ab568777d44aa21206dfb8807a840990c4037523b51812/watchfiles-1.2.0-cp314-cp314-win32.whl", hash = "sha256:c0db965c5f79aa49fe672d297cf1febc5ad149b658594944f49a54a2b96270a7", size = 275108, upload-time = "2026-05-18T04:30:06.891Z" }, + { url = "https://files.pythonhosted.org/packages/92/45/190ce6db8dcb4536682cf75d3889ff1a27182a58cb519d343cb6d9ea63d8/watchfiles-1.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:71283b39fd17e5408eb123bd37aeecfd9d54c81fc184421943208aadb879d103", size = 288441, upload-time = "2026-05-18T04:32:12.901Z" }, + { url = "https://files.pythonhosted.org/packages/74/0d/3eae1c2313ab08378431d907c3f8095ecca00f3eda33111cf4f0f2591799/watchfiles-1.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:c5c19526f4e54a00f2666a6c0e9e40d582c09e865055ea7378bf0009aab857b3", size = 280684, upload-time = "2026-05-18T04:31:26.902Z" }, + { url = "https://files.pythonhosted.org/packages/b1/75/fb64e6c25d6b5ca636d03df34ffb1c6e9873303e76d27967e045f8df088f/watchfiles-1.2.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:d73a585accffa5ae39c17264c36ec3166d2fad7000c780f5ef83b2722afb9dd2", size = 398857, upload-time = "2026-05-18T04:32:17.108Z" }, + { url = "https://files.pythonhosted.org/packages/73/4e/9f7adf01754cbf81843722ccfec169d8f26c69778281a302855cecd2ee08/watchfiles-1.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ae99b14c5f21e026e0e9d96f40e07d8570ebee6cafd9d8fc318354606daa7a28", size = 392413, upload-time = "2026-05-18T04:31:07.911Z" }, + { url = "https://files.pythonhosted.org/packages/47/c8/bec626bcc2d69f44b9acb24ce7d60ed7b16b73628eea747fcbd169d8edda/watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4429f3b105524a10b72c3a819b091c495d2811d419c1e1e8df773a5a5974f831", size = 452409, upload-time = "2026-05-18T04:31:20.142Z" }, + { url = "https://files.pythonhosted.org/packages/00/b7/b6362068e81e7c556d155a34c35d40ac3ef42d747b06d7f6e5bf58e359c2/watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:43d818978d06062d9b22c4fab2ebe44cf5213d42dc8e62bda8c2760cfa2eeb33", size = 458827, upload-time = "2026-05-18T04:32:06.219Z" }, + { url = "https://files.pythonhosted.org/packages/67/f8/9a813fa42afb1e0b4625e75f0479826644d3ee8dc287e093799bc01f390c/watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9f732dc58b2dbe69e464ccf8fff7a03b0dd0be439da4c0720d3558527d3d6b4", size = 490104, upload-time = "2026-05-18T04:31:56.034Z" }, + { url = "https://files.pythonhosted.org/packages/2f/bf/27dfb6094ca4c9aad21298b5525b6c53cb36121ee454331d05161e58d130/watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f200104103feb097de4cab8fe4f5dd18a2026934c7dea98c55a2f5fd6d5a33b", size = 571360, upload-time = "2026-05-18T04:31:57.133Z" }, + { url = "https://files.pythonhosted.org/packages/fb/39/44a096d67270ea93df91d33877dbe91fbda3aa4f8ec2edf799d93eda8736/watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:63ac26eefbf4af1741247d6fb68b11c49a25b2f7413fbd318a83a12aaa9cf666", size = 464644, upload-time = "2026-05-18T04:30:57.33Z" }, + { url = "https://files.pythonhosted.org/packages/0e/80/c7472203bad6268e3ef1ad260739704847898938ad7ea8b63a5131f46b50/watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c4997d4e4a55f0d02b6cde327322daf3a0400e5df6c6b15948994bf72497925", size = 454771, upload-time = "2026-05-18T04:30:48.736Z" }, + { url = "https://files.pythonhosted.org/packages/51/cf/3b10b268b4b7f0fc26e9debb5eef1998b515887840f444cd3ec80c688755/watchfiles-1.2.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:4c887eba18b7945ac73067a8b4a66f21cd46c2539b2bc68588f7be6c7eb6d26b", size = 463494, upload-time = "2026-05-18T04:31:33.826Z" }, + { url = "https://files.pythonhosted.org/packages/3d/3e/a4302545cd589262a0dc7d140e86f7688eba3f9c72776c27f7e23b8864c4/watchfiles-1.2.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:3416ff151bb6b5a8d8d11664974fbef4d9305b9b2957839ab5a270468fd8df30", size = 629383, upload-time = "2026-05-18T04:31:15.596Z" }, + { url = "https://files.pythonhosted.org/packages/db/99/d5649df0a9a410d45b7c882304d0b790903ac9b6e8f2cfd12114e0c6b9f2/watchfiles-1.2.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:0e831a271c035d89789cffc386b6aa1375f39f1cd25eb7ca0997e4970d152fc5", size = 656093, upload-time = "2026-05-18T04:31:58.707Z" }, + { url = "https://files.pythonhosted.org/packages/92/b9/362702539275019a54dd2e94511b31a9b89c5f9e6a21966de7eb692549fc/watchfiles-1.2.0-cp315-cp315-macosx_10_12_x86_64.whl", hash = "sha256:37a6721cdf3f65dbb13aa9503510ccb4451603ac837e44d265d7992a597e1374", size = 400109, upload-time = "2026-05-18T04:31:16.879Z" }, + { url = "https://files.pythonhosted.org/packages/8f/75/71d5ba62db781e5587bded1d944c675374bc4aa37ff33d5018d98e8b6538/watchfiles-1.2.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:2b37d10b5a63bd4d87e18472d80fa525bd670586fae62e5dd580452764879b65", size = 392167, upload-time = "2026-05-18T04:31:28.058Z" }, + { url = "https://files.pythonhosted.org/packages/3c/01/c66dd95d0423fe30d31820e2d1d5bda773764131bbb6ac0cb1cf303ac328/watchfiles-1.2.0-cp315-cp315-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a105bc2283f67e8fbec74253ec2d94925de92ed72c0393f1206bf326b7b7b69", size = 452372, upload-time = "2026-05-18T04:31:00.836Z" }, + { url = "https://files.pythonhosted.org/packages/91/15/2fe99557e72f85627c6a8eed50d889e8d101623e060a22ad75b875cb932d/watchfiles-1.2.0-cp315-cp315-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5327989a465505f05cfe06f04fa9d0c2fd5432bb243e10e6f012b1bdca3c8579", size = 459596, upload-time = "2026-05-18T04:31:34.96Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/d4acfa0023367428ed48351b3b9b267893037b6cadae55620c61c24bcfd4/watchfiles-1.2.0-cp315-cp315-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ecb47f183a8025b2aa18b546725c3657e542112ae9c0613a2af79b4fa8d04ad7", size = 490869, upload-time = "2026-05-18T04:31:59.923Z" }, + { url = "https://files.pythonhosted.org/packages/a4/5f/3164cbdce06c9fb95c4f7b9e2f9760b5e2797af43a9ecc317ef42a23a278/watchfiles-1.2.0-cp315-cp315-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8520a4ab0e37f770afc34459c4f8f7019e153f9124dc101c15538365875d1ab2", size = 571641, upload-time = "2026-05-18T04:32:00.948Z" }, + { url = "https://files.pythonhosted.org/packages/41/e6/85d3731c55e65cd7690f3f803d24c139588aaf863e4bf2148fe7a7fa1a19/watchfiles-1.2.0-cp315-cp315-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:71cd71740ed2c15211ebb237ced4e39a1cdf6f80566e5fe95428da1626f4fde6", size = 464444, upload-time = "2026-05-18T04:30:34.298Z" }, + { url = "https://files.pythonhosted.org/packages/f4/7d/562641012b8b09872742c3b8adf9629ec479fd78f8d68ae4a0c13da8add6/watchfiles-1.2.0-cp315-cp315-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f88af53d6ddaf72179ef613ddc905e6f4785f712b49b80b3bef9f3525e6194b4", size = 453593, upload-time = "2026-05-18T04:31:23.464Z" }, + { url = "https://files.pythonhosted.org/packages/56/fe/cb8ef3d6f929d14158fdaaad9925985b7310abc9384dcd4d82dd0016fb59/watchfiles-1.2.0-cp315-cp315-manylinux_2_31_riscv64.whl", hash = "sha256:cee9d5efd929efdac5f7e58f72b3376f676b64050a91c5b99a7094c5b2317488", size = 465096, upload-time = "2026-05-18T04:31:30.384Z" }, + { url = "https://files.pythonhosted.org/packages/25/91/80908e835e100527a9267147b08c0eee1fa6ab0ffec15edc04d1d44885f7/watchfiles-1.2.0-cp315-cp315-musllinux_1_1_aarch64.whl", hash = "sha256:b718bf356bbc15e559bd8ef41782b573b8ae0e3f177ab244b440568d7ea02cfb", size = 630638, upload-time = "2026-05-18T04:30:49.89Z" }, + { url = "https://files.pythonhosted.org/packages/46/4b/95ab2f256bb4af3cb2eb23b9317bda984ee6e0f11733a5c004a6c95b06e3/watchfiles-1.2.0-cp315-cp315-musllinux_1_1_x86_64.whl", hash = "sha256:922c0e019fe68b3ae392965a766b02a71ba1168c932cebc3733cd52c5fe5b377", size = 657684, upload-time = "2026-05-18T04:31:32.027Z" }, + { url = "https://files.pythonhosted.org/packages/23/f4/7513ef1e85fc4c6331b59479d6d72661fc391fbe543678052ac72c8b6c19/watchfiles-1.2.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:4674d49eb94706dfe666c069fc0a1b646ffcf920473492e209f6d5f60d3f0cc2", size = 403050, upload-time = "2026-05-18T04:30:36.753Z" }, + { url = "https://files.pythonhosted.org/packages/27/0b/a54103cfd732bb703c7a749222011a0483ef3705948dae3b203158601119/watchfiles-1.2.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:094b9b70103d4e963499bdea001ee3c2697b144cd9ae6218a62c0f89ec9e31db", size = 396629, upload-time = "2026-05-18T04:32:03.268Z" }, + { url = "https://files.pythonhosted.org/packages/5e/2c/73f31a3b893886206c3f54d73e8ad8dee58cdb2f69ad2622e0a8a9e07f4e/watchfiles-1.2.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0ef001f8c25ad0fa9529f914c1600647ecd0f542d11c19b7894768c67b6acb7", size = 457318, upload-time = "2026-05-18T04:31:01.932Z" }, + { url = "https://files.pythonhosted.org/packages/e9/f9/45d021e4a5cc7b9dd567f7cbb06d3b75f751a690063fb6cc7ec60f4e46b7/watchfiles-1.2.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a88fc94e647bc4eec523f1caa540258eb71d14278b9daf72fa1e2658a98df0f0", size = 457771, upload-time = "2026-05-18T04:30:56.331Z" }, +] + +[[package]] +name = "wcwidth" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/ee/afaf0f85a9a18fe47a67f1e4422ed6cf1fe642f0ae0a2f81166231303c52/wcwidth-0.7.0.tar.gz", hash = "sha256:90e3a7ea092341c44b99562e75d09e4d5160fe7a3974c6fb842a101a95e7eed0", size = 182132, upload-time = "2026-05-02T16:04:12.653Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/52/e465037f5375f43533d1a80b6923955201596a99142ed524d77b571a1418/wcwidth-0.7.0-py3-none-any.whl", hash = "sha256:5d69154c429a82910e241c738cd0e2976fac8a2dd47a1a805f4afed1c0f136f2", size = 110825, upload-time = "2026-05-02T16:04:11.033Z" }, +] + +[[package]] +name = "websockets" +version = "16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/04/24/4b2031d72e840ce4c1ccb255f693b15c334757fc50023e4db9537080b8c4/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5", size = 179346, upload-time = "2026-01-10T09:23:47.181Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/db/de907251b4ff46ae804ad0409809504153b3f30984daf82a1d84a9875830/websockets-16.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:31a52addea25187bde0797a97d6fc3d2f92b6f72a9370792d65a6e84615ac8a8", size = 177340, upload-time = "2026-01-10T09:22:34.539Z" }, + { url = "https://files.pythonhosted.org/packages/f3/fa/abe89019d8d8815c8781e90d697dec52523fb8ebe308bf11664e8de1877e/websockets-16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:417b28978cdccab24f46400586d128366313e8a96312e4b9362a4af504f3bbad", size = 175022, upload-time = "2026-01-10T09:22:36.332Z" }, + { url = "https://files.pythonhosted.org/packages/58/5d/88ea17ed1ded2079358b40d31d48abe90a73c9e5819dbcde1606e991e2ad/websockets-16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:af80d74d4edfa3cb9ed973a0a5ba2b2a549371f8a741e0800cb07becdd20f23d", size = 175319, upload-time = "2026-01-10T09:22:37.602Z" }, + { url = "https://files.pythonhosted.org/packages/d2/ae/0ee92b33087a33632f37a635e11e1d99d429d3d323329675a6022312aac2/websockets-16.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:08d7af67b64d29823fed316505a89b86705f2b7981c07848fb5e3ea3020c1abe", size = 184631, upload-time = "2026-01-10T09:22:38.789Z" }, + { url = "https://files.pythonhosted.org/packages/c8/c5/27178df583b6c5b31b29f526ba2da5e2f864ecc79c99dae630a85d68c304/websockets-16.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7be95cfb0a4dae143eaed2bcba8ac23f4892d8971311f1b06f3c6b78952ee70b", size = 185870, upload-time = "2026-01-10T09:22:39.893Z" }, + { url = "https://files.pythonhosted.org/packages/87/05/536652aa84ddc1c018dbb7e2c4cbcd0db884580bf8e95aece7593fde526f/websockets-16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d6297ce39ce5c2e6feb13c1a996a2ded3b6832155fcfc920265c76f24c7cceb5", size = 185361, upload-time = "2026-01-10T09:22:41.016Z" }, + { url = "https://files.pythonhosted.org/packages/6d/e2/d5332c90da12b1e01f06fb1b85c50cfc489783076547415bf9f0a659ec19/websockets-16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1c1b30e4f497b0b354057f3467f56244c603a79c0d1dafce1d16c283c25f6e64", size = 184615, upload-time = "2026-01-10T09:22:42.442Z" }, + { url = "https://files.pythonhosted.org/packages/77/fb/d3f9576691cae9253b51555f841bc6600bf0a983a461c79500ace5a5b364/websockets-16.0-cp311-cp311-win32.whl", hash = "sha256:5f451484aeb5cafee1ccf789b1b66f535409d038c56966d6101740c1614b86c6", size = 178246, upload-time = "2026-01-10T09:22:43.654Z" }, + { url = "https://files.pythonhosted.org/packages/54/67/eaff76b3dbaf18dcddabc3b8c1dba50b483761cccff67793897945b37408/websockets-16.0-cp311-cp311-win_amd64.whl", hash = "sha256:8d7f0659570eefb578dacde98e24fb60af35350193e4f56e11190787bee77dac", size = 178684, upload-time = "2026-01-10T09:22:44.941Z" }, + { url = "https://files.pythonhosted.org/packages/84/7b/bac442e6b96c9d25092695578dda82403c77936104b5682307bd4deb1ad4/websockets-16.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:71c989cbf3254fbd5e84d3bff31e4da39c43f884e64f2551d14bb3c186230f00", size = 177365, upload-time = "2026-01-10T09:22:46.787Z" }, + { url = "https://files.pythonhosted.org/packages/b0/fe/136ccece61bd690d9c1f715baaeefd953bb2360134de73519d5df19d29ca/websockets-16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8b6e209ffee39ff1b6d0fa7bfef6de950c60dfb91b8fcead17da4ee539121a79", size = 175038, upload-time = "2026-01-10T09:22:47.999Z" }, + { url = "https://files.pythonhosted.org/packages/40/1e/9771421ac2286eaab95b8575b0cb701ae3663abf8b5e1f64f1fd90d0a673/websockets-16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86890e837d61574c92a97496d590968b23c2ef0aeb8a9bc9421d174cd378ae39", size = 175328, upload-time = "2026-01-10T09:22:49.809Z" }, + { url = "https://files.pythonhosted.org/packages/18/29/71729b4671f21e1eaa5d6573031ab810ad2936c8175f03f97f3ff164c802/websockets-16.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9b5aca38b67492ef518a8ab76851862488a478602229112c4b0d58d63a7a4d5c", size = 184915, upload-time = "2026-01-10T09:22:51.071Z" }, + { url = "https://files.pythonhosted.org/packages/97/bb/21c36b7dbbafc85d2d480cd65df02a1dc93bf76d97147605a8e27ff9409d/websockets-16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e0334872c0a37b606418ac52f6ab9cfd17317ac26365f7f65e203e2d0d0d359f", size = 186152, upload-time = "2026-01-10T09:22:52.224Z" }, + { url = "https://files.pythonhosted.org/packages/4a/34/9bf8df0c0cf88fa7bfe36678dc7b02970c9a7d5e065a3099292db87b1be2/websockets-16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a0b31e0b424cc6b5a04b8838bbaec1688834b2383256688cf47eb97412531da1", size = 185583, upload-time = "2026-01-10T09:22:53.443Z" }, + { url = "https://files.pythonhosted.org/packages/47/88/4dd516068e1a3d6ab3c7c183288404cd424a9a02d585efbac226cb61ff2d/websockets-16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:485c49116d0af10ac698623c513c1cc01c9446c058a4e61e3bf6c19dff7335a2", size = 184880, upload-time = "2026-01-10T09:22:55.033Z" }, + { url = "https://files.pythonhosted.org/packages/91/d6/7d4553ad4bf1c0421e1ebd4b18de5d9098383b5caa1d937b63df8d04b565/websockets-16.0-cp312-cp312-win32.whl", hash = "sha256:eaded469f5e5b7294e2bdca0ab06becb6756ea86894a47806456089298813c89", size = 178261, upload-time = "2026-01-10T09:22:56.251Z" }, + { url = "https://files.pythonhosted.org/packages/c3/f0/f3a17365441ed1c27f850a80b2bc680a0fa9505d733fe152fdf5e98c1c0b/websockets-16.0-cp312-cp312-win_amd64.whl", hash = "sha256:5569417dc80977fc8c2d43a86f78e0a5a22fee17565d78621b6bb264a115d4ea", size = 178693, upload-time = "2026-01-10T09:22:57.478Z" }, + { url = "https://files.pythonhosted.org/packages/cc/9c/baa8456050d1c1b08dd0ec7346026668cbc6f145ab4e314d707bb845bf0d/websockets-16.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:878b336ac47938b474c8f982ac2f7266a540adc3fa4ad74ae96fea9823a02cc9", size = 177364, upload-time = "2026-01-10T09:22:59.333Z" }, + { url = "https://files.pythonhosted.org/packages/7e/0c/8811fc53e9bcff68fe7de2bcbe75116a8d959ac699a3200f4847a8925210/websockets-16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:52a0fec0e6c8d9a784c2c78276a48a2bdf099e4ccc2a4cad53b27718dbfd0230", size = 175039, upload-time = "2026-01-10T09:23:01.171Z" }, + { url = "https://files.pythonhosted.org/packages/aa/82/39a5f910cb99ec0b59e482971238c845af9220d3ab9fa76dd9162cda9d62/websockets-16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e6578ed5b6981005df1860a56e3617f14a6c307e6a71b4fff8c48fdc50f3ed2c", size = 175323, upload-time = "2026-01-10T09:23:02.341Z" }, + { url = "https://files.pythonhosted.org/packages/bd/28/0a25ee5342eb5d5f297d992a77e56892ecb65e7854c7898fb7d35e9b33bd/websockets-16.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:95724e638f0f9c350bb1c2b0a7ad0e83d9cc0c9259f3ea94e40d7b02a2179ae5", size = 184975, upload-time = "2026-01-10T09:23:03.756Z" }, + { url = "https://files.pythonhosted.org/packages/f9/66/27ea52741752f5107c2e41fda05e8395a682a1e11c4e592a809a90c6a506/websockets-16.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0204dc62a89dc9d50d682412c10b3542d748260d743500a85c13cd1ee4bde82", size = 186203, upload-time = "2026-01-10T09:23:05.01Z" }, + { url = "https://files.pythonhosted.org/packages/37/e5/8e32857371406a757816a2b471939d51c463509be73fa538216ea52b792a/websockets-16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:52ac480f44d32970d66763115edea932f1c5b1312de36df06d6b219f6741eed8", size = 185653, upload-time = "2026-01-10T09:23:06.301Z" }, + { url = "https://files.pythonhosted.org/packages/9b/67/f926bac29882894669368dc73f4da900fcdf47955d0a0185d60103df5737/websockets-16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6e5a82b677f8f6f59e8dfc34ec06ca6b5b48bc4fcda346acd093694cc2c24d8f", size = 184920, upload-time = "2026-01-10T09:23:07.492Z" }, + { url = "https://files.pythonhosted.org/packages/3c/a1/3d6ccdcd125b0a42a311bcd15a7f705d688f73b2a22d8cf1c0875d35d34a/websockets-16.0-cp313-cp313-win32.whl", hash = "sha256:abf050a199613f64c886ea10f38b47770a65154dc37181bfaff70c160f45315a", size = 178255, upload-time = "2026-01-10T09:23:09.245Z" }, + { url = "https://files.pythonhosted.org/packages/6b/ae/90366304d7c2ce80f9b826096a9e9048b4bb760e44d3b873bb272cba696b/websockets-16.0-cp313-cp313-win_amd64.whl", hash = "sha256:3425ac5cf448801335d6fdc7ae1eb22072055417a96cc6b31b3861f455fbc156", size = 178689, upload-time = "2026-01-10T09:23:10.483Z" }, + { url = "https://files.pythonhosted.org/packages/f3/1d/e88022630271f5bd349ed82417136281931e558d628dd52c4d8621b4a0b2/websockets-16.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8cc451a50f2aee53042ac52d2d053d08bf89bcb31ae799cb4487587661c038a0", size = 177406, upload-time = "2026-01-10T09:23:12.178Z" }, + { url = "https://files.pythonhosted.org/packages/f2/78/e63be1bf0724eeb4616efb1ae1c9044f7c3953b7957799abb5915bffd38e/websockets-16.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:daa3b6ff70a9241cf6c7fc9e949d41232d9d7d26fd3522b1ad2b4d62487e9904", size = 175085, upload-time = "2026-01-10T09:23:13.511Z" }, + { url = "https://files.pythonhosted.org/packages/bb/f4/d3c9220d818ee955ae390cf319a7c7a467beceb24f05ee7aaaa2414345ba/websockets-16.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fd3cb4adb94a2a6e2b7c0d8d05cb94e6f1c81a0cf9dc2694fb65c7e8d94c42e4", size = 175328, upload-time = "2026-01-10T09:23:14.727Z" }, + { url = "https://files.pythonhosted.org/packages/63/bc/d3e208028de777087e6fb2b122051a6ff7bbcca0d6df9d9c2bf1dd869ae9/websockets-16.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:781caf5e8eee67f663126490c2f96f40906594cb86b408a703630f95550a8c3e", size = 185044, upload-time = "2026-01-10T09:23:15.939Z" }, + { url = "https://files.pythonhosted.org/packages/ad/6e/9a0927ac24bd33a0a9af834d89e0abc7cfd8e13bed17a86407a66773cc0e/websockets-16.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:caab51a72c51973ca21fa8a18bd8165e1a0183f1ac7066a182ff27107b71e1a4", size = 186279, upload-time = "2026-01-10T09:23:17.148Z" }, + { url = "https://files.pythonhosted.org/packages/b9/ca/bf1c68440d7a868180e11be653c85959502efd3a709323230314fda6e0b3/websockets-16.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:19c4dc84098e523fd63711e563077d39e90ec6702aff4b5d9e344a60cb3c0cb1", size = 185711, upload-time = "2026-01-10T09:23:18.372Z" }, + { url = "https://files.pythonhosted.org/packages/c4/f8/fdc34643a989561f217bb477cbc47a3a07212cbda91c0e4389c43c296ebf/websockets-16.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a5e18a238a2b2249c9a9235466b90e96ae4795672598a58772dd806edc7ac6d3", size = 184982, upload-time = "2026-01-10T09:23:19.652Z" }, + { url = "https://files.pythonhosted.org/packages/dd/d1/574fa27e233764dbac9c52730d63fcf2823b16f0856b3329fc6268d6ae4f/websockets-16.0-cp314-cp314-win32.whl", hash = "sha256:a069d734c4a043182729edd3e9f247c3b2a4035415a9172fd0f1b71658a320a8", size = 177915, upload-time = "2026-01-10T09:23:21.458Z" }, + { url = "https://files.pythonhosted.org/packages/8a/f1/ae6b937bf3126b5134ce1f482365fde31a357c784ac51852978768b5eff4/websockets-16.0-cp314-cp314-win_amd64.whl", hash = "sha256:c0ee0e63f23914732c6d7e0cce24915c48f3f1512ec1d079ed01fc629dab269d", size = 178381, upload-time = "2026-01-10T09:23:22.715Z" }, + { url = "https://files.pythonhosted.org/packages/06/9b/f791d1db48403e1f0a27577a6beb37afae94254a8c6f08be4a23e4930bc0/websockets-16.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:a35539cacc3febb22b8f4d4a99cc79b104226a756aa7400adc722e83b0d03244", size = 177737, upload-time = "2026-01-10T09:23:24.523Z" }, + { url = "https://files.pythonhosted.org/packages/bd/40/53ad02341fa33b3ce489023f635367a4ac98b73570102ad2cdd770dacc9a/websockets-16.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:b784ca5de850f4ce93ec85d3269d24d4c82f22b7212023c974c401d4980ebc5e", size = 175268, upload-time = "2026-01-10T09:23:25.781Z" }, + { url = "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:569d01a4e7fba956c5ae4fc988f0d4e187900f5497ce46339c996dbf24f17641", size = 175486, upload-time = "2026-01-10T09:23:27.033Z" }, + { url = "https://files.pythonhosted.org/packages/e5/2d/7583b30208b639c8090206f95073646c2c9ffd66f44df967981a64f849ad/websockets-16.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:50f23cdd8343b984957e4077839841146f67a3d31ab0d00e6b824e74c5b2f6e8", size = 185331, upload-time = "2026-01-10T09:23:28.259Z" }, + { url = "https://files.pythonhosted.org/packages/45/b0/cce3784eb519b7b5ad680d14b9673a31ab8dcb7aad8b64d81709d2430aa8/websockets-16.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:152284a83a00c59b759697b7f9e9cddf4e3c7861dd0d964b472b70f78f89e80e", size = 186501, upload-time = "2026-01-10T09:23:29.449Z" }, + { url = "https://files.pythonhosted.org/packages/19/60/b8ebe4c7e89fb5f6cdf080623c9d92789a53636950f7abacfc33fe2b3135/websockets-16.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bc59589ab64b0022385f429b94697348a6a234e8ce22544e3681b2e9331b5944", size = 186062, upload-time = "2026-01-10T09:23:31.368Z" }, + { url = "https://files.pythonhosted.org/packages/88/a8/a080593f89b0138b6cba1b28f8df5673b5506f72879322288b031337c0b8/websockets-16.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:32da954ffa2814258030e5a57bc73a3635463238e797c7375dc8091327434206", size = 185356, upload-time = "2026-01-10T09:23:32.627Z" }, + { url = "https://files.pythonhosted.org/packages/c2/b6/b9afed2afadddaf5ebb2afa801abf4b0868f42f8539bfe4b071b5266c9fe/websockets-16.0-cp314-cp314t-win32.whl", hash = "sha256:5a4b4cc550cb665dd8a47f868c8d04c8230f857363ad3c9caf7a0c3bf8c61ca6", size = 178085, upload-time = "2026-01-10T09:23:33.816Z" }, + { url = "https://files.pythonhosted.org/packages/9f/3e/28135a24e384493fa804216b79a6a6759a38cc4ff59118787b9fb693df93/websockets-16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b14dc141ed6d2dde437cddb216004bcac6a1df0935d79656387bd41632ba0bbd", size = 178531, upload-time = "2026-01-10T09:23:35.016Z" }, + { url = "https://files.pythonhosted.org/packages/72/07/c98a68571dcf256e74f1f816b8cc5eae6eb2d3d5cfa44d37f801619d9166/websockets-16.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:349f83cd6c9a415428ee1005cadb5c2c56f4389bc06a9af16103c3bc3dcc8b7d", size = 174947, upload-time = "2026-01-10T09:23:36.166Z" }, + { url = "https://files.pythonhosted.org/packages/7e/52/93e166a81e0305b33fe416338be92ae863563fe7bce446b0f687b9df5aea/websockets-16.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:4a1aba3340a8dca8db6eb5a7986157f52eb9e436b74813764241981ca4888f03", size = 175260, upload-time = "2026-01-10T09:23:37.409Z" }, + { url = "https://files.pythonhosted.org/packages/56/0c/2dbf513bafd24889d33de2ff0368190a0e69f37bcfa19009ef819fe4d507/websockets-16.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f4a32d1bd841d4bcbffdcb3d2ce50c09c3909fbead375ab28d0181af89fd04da", size = 176071, upload-time = "2026-01-10T09:23:39.158Z" }, + { url = "https://files.pythonhosted.org/packages/a5/8f/aea9c71cc92bf9b6cc0f7f70df8f0b420636b6c96ef4feee1e16f80f75dd/websockets-16.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0298d07ee155e2e9fda5be8a9042200dd2e3bb0b8a38482156576f863a9d457c", size = 176968, upload-time = "2026-01-10T09:23:41.031Z" }, + { url = "https://files.pythonhosted.org/packages/9a/3f/f70e03f40ffc9a30d817eef7da1be72ee4956ba8d7255c399a01b135902a/websockets-16.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:a653aea902e0324b52f1613332ddf50b00c06fdaf7e92624fbf8c77c78fa5767", size = 178735, upload-time = "2026-01-10T09:23:42.259Z" }, + { url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" }, +] + +[[package]] +name = "widgetsnbextension" +version = "4.0.15" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/f4/c67440c7fb409a71b7404b7aefcd7569a9c0d6bd071299bf4198ae7a5d95/widgetsnbextension-4.0.15.tar.gz", hash = "sha256:de8610639996f1567952d763a5a41af8af37f2575a41f9852a38f947eb82a3b9", size = 1097402, upload-time = "2025-11-01T21:15:55.178Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl", hash = "sha256:8156704e4346a571d9ce73b84bee86a29906c9abfd7223b7228a28899ccf3366", size = 2196503, upload-time = "2025-11-01T21:15:53.565Z" }, +] diff --git a/data/.gitkeep b/data/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/dev.ps1 b/dev.ps1 new file mode 100644 index 0000000..1744a87 --- /dev/null +++ b/dev.ps1 @@ -0,0 +1,242 @@ +# tf-stocks-panel - one-shot launcher for backend + frontend (Windows / PowerShell) +# +# Usage: +# .\dev.ps1 +# .\dev.ps1 -BackendPort 8000 -FrontendPort 5173 +# $env:BACKEND_PORT='8000'; .\dev.ps1 +# +# Ctrl-C closes both processes. +# +# If you see "running scripts is disabled": +# Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned + +[CmdletBinding()] +param( + [int]$BackendPort = 0, + [int]$FrontendPort = 0 +) + +$ErrorActionPreference = 'Stop' + +# Port precedence: CLI arg > env var > default +if ($BackendPort -le 0) { $BackendPort = if ($env:BACKEND_PORT) { [int]$env:BACKEND_PORT } else { 3018 } } +if ($FrontendPort -le 0) { $FrontendPort = if ($env:FRONTEND_PORT) { [int]$env:FRONTEND_PORT } else { 3011 } } + +# Force UTF-8 console output so child process logs aren't garbled +try { + [Console]::OutputEncoding = New-Object System.Text.UTF8Encoding $false + $OutputEncoding = New-Object System.Text.UTF8Encoding $false +} catch {} + +$Root = Split-Path -Parent $MyInvocation.MyCommand.Path +$BackendDir = Join-Path $Root 'backend' +$FrontendDir = Join-Path $Root 'frontend' + +function Log-Info($m) { Write-Host "[dev] $m" -ForegroundColor DarkGray } +function Log-Ok ($m) { Write-Host "[dev] $m" -ForegroundColor Green } +function Log-Warn($m) { Write-Host "[dev] $m" -ForegroundColor Yellow } +function Log-Err ($m) { Write-Host "[dev] $m" -ForegroundColor Red } + +# ===== 1. Dependency check ===== +function Require-Cmd($cmd, $hint) { + if (-not (Get-Command $cmd -ErrorAction SilentlyContinue)) { + Log-Err "$cmd not found" + Write-Host " install via: $hint" + exit 1 + } +} + +Require-Cmd 'uv' 'powershell -c "irm https://astral.sh/uv/install.ps1 | iex" OR winget install --id=astral-sh.uv' +Require-Cmd 'pnpm' 'npm i -g pnpm OR corepack enable; corepack prepare pnpm@9 --activate' + +# ===== 2. Port check - kill anything listening on the target ports ===== +function Free-Port($name, $port) { + $conns = Get-NetTCPConnection -State Listen -LocalPort $port -ErrorAction SilentlyContinue + if (-not $conns) { return } + $pids = @($conns.OwningProcess | Where-Object { $_ -gt 0 } | Sort-Object -Unique) + if ($pids.Count -eq 0) { return } + + # Filter to PIDs that still exist as running processes. + # A zombie TCP endpoint can linger after the process is already dead. + $alive = @($pids | Where-Object { + try { [System.Diagnostics.Process]::GetProcessById($_) | Out-Null; $true } + catch { $false } + }) + + if ($alive.Count -eq 0) { + # All processes are dead but kernel still holds the socket (zombie endpoint). + # On Windows this can linger for minutes, but uvicorn/vite can still bind + # via SO_REUSEADDR — no point waiting, just proceed. + Log-Warn "port ${port} (${name}) - zombie socket (processes gone), starting anyway" + return + } + + Log-Warn "port $port ($name) is in use, killing PID: $($alive -join ', ')" + # Use taskkill /F /T to kill the entire process tree (parent + children), + # not just the parent. Stop-Process only kills one process, leaving child + # processes (e.g. uvicorn spawned by uv) as orphans holding the socket. + foreach ($p in $alive) { + # Suppress stderr properly for Windows PowerShell (5.x) + $null = & cmd /c "taskkill /F /T /PID $p 2>nul" + # Fallback: if taskkill failed, try Stop-Process + try { Stop-Process -Id $p -Force -ErrorAction SilentlyContinue } catch {} + } + + # Wait up to 5 seconds for the kernel to release the TCP endpoint + for ($i = 0; $i -lt 10; $i++) { + Start-Sleep -Milliseconds 500 + $still = Get-NetTCPConnection -State Listen -LocalPort $port -ErrorAction SilentlyContinue + if (-not $still) { + Log-Ok "port $port freed" + return + } + } + + # Port still stuck — process might be dead with zombie socket + $anyAlive = $still | Where-Object { + try { [System.Diagnostics.Process]::GetProcessById($_.OwningProcess) | Out-Null; $true } + catch { $false } + } + if ($anyAlive.Count -eq 0) { + Log-Warn "port ${port} - processes gone but socket lingers, starting anyway" + } else { + Log-Err "port ${port} still in use by live process(es). Inspect: Get-NetTCPConnection -LocalPort ${port}" + exit 1 + } +} + +Free-Port 'backend' $BackendPort +Free-Port 'frontend' $FrontendPort + +# ===== 3. First-time dependency install ===== +if (-not (Test-Path (Join-Path $BackendDir '.venv'))) { + Log-Info 'first run - installing Python deps (1-2 min)...' + Push-Location $BackendDir + try { & uv sync } finally { Pop-Location } + if ($LASTEXITCODE -ne 0) { Log-Err 'uv sync failed'; exit 1 } + Log-Ok 'backend deps installed' +} + +if (-not (Test-Path (Join-Path $FrontendDir 'node_modules'))) { + Log-Info 'first run - installing Node deps...' + Push-Location $FrontendDir + try { & pnpm install } finally { Pop-Location } + if ($LASTEXITCODE -ne 0) { Log-Err 'pnpm install failed'; exit 1 } + Log-Ok 'frontend deps installed' +} + +# ===== 4. Banner (ASCII so it renders on any codepage) ===== +Write-Host '' +Write-Host '+----------------------------------------------+' -ForegroundColor Blue +Write-Host '| tf-stocks-panel |' -ForegroundColor Blue +Write-Host '| |' -ForegroundColor Blue +Write-Host "| backend http://localhost:$BackendPort" -ForegroundColor Blue +Write-Host "| frontend http://localhost:$FrontendPort" -ForegroundColor Blue +Write-Host '| |' -ForegroundColor Blue +Write-Host '| Ctrl-C closes both |' -ForegroundColor Blue +Write-Host '+----------------------------------------------+' -ForegroundColor Blue +Write-Host '' + +# ===== 5. Launch jobs ===== +# Each job writes its $PID to a temp file so the main thread can find the +# child powershell.exe and taskkill /T the whole process tree on exit. +$backendPidFile = [System.IO.Path]::GetTempFileName() +$frontendPidFile = [System.IO.Path]::GetTempFileName() + +$backendJob = Start-Job -Name 'backend' -ScriptBlock { + param($pidFile, $dir, $port) + $PID | Out-File -FilePath $pidFile -Encoding ascii -Force + $env:PYTHONUNBUFFERED = '1' + Set-Location $dir + & .\.venv\Scripts\python.exe -m uvicorn app.main:app --reload --port $port 2>&1 +} -ArgumentList $backendPidFile, $BackendDir, $BackendPort + +$frontendJob = Start-Job -Name 'frontend' -ScriptBlock { + param($pidFile, $dir, $port) + $PID | Out-File -FilePath $pidFile -Encoding ascii -Force + Set-Location $dir + & pnpm dev --port $port 2>&1 +} -ArgumentList $frontendPidFile, $FrontendDir, $FrontendPort + +# Wait up to 5 seconds for the PID files to materialise +function Read-JobPid($file) { + for ($i = 0; $i -lt 50; $i++) { + try { + $c = (Get-Content $file -ErrorAction SilentlyContinue) -as [string] + if ($c -and $c.Trim()) { return [int]$c.Trim() } + } catch {} + Start-Sleep -Milliseconds 100 + } + return $null +} +$backendChildPid = Read-JobPid $backendPidFile +$frontendChildPid = Read-JobPid $frontendPidFile + +# ===== 6. Cleanup ===== +$script:cleaning = $false +function Cleanup-All { + if ($script:cleaning) { return } + $script:cleaning = $true + Write-Host '' + Log-Info 'shutting down...' + + foreach ($p in @($backendChildPid, $frontendChildPid)) { + if ($p) { + # /T kills the whole process tree (the job's powershell + uvicorn/vite) + $null = & cmd /c "taskkill /F /T /PID $p 2>nul" + } + } + foreach ($j in @($backendJob, $frontendJob)) { + if ($j) { + Stop-Job $j -ErrorAction SilentlyContinue + Remove-Job $j -Force -ErrorAction SilentlyContinue + } + } + foreach ($f in @($backendPidFile, $frontendPidFile)) { + Remove-Item $f -Force -ErrorAction SilentlyContinue + } + Log-Ok 'bye' +} + +# ===== 7. Main loop - pump output, handle Ctrl-C ===== +# Treat Ctrl-C as input so try/finally is guaranteed to run. +$prevCtrlC = [Console]::TreatControlCAsInput +try { + [Console]::TreatControlCAsInput = $true + + while ($true) { + if ([Console]::KeyAvailable) { + $key = [Console]::ReadKey($true) + if (($key.Modifiers -band [ConsoleModifiers]::Control) -and $key.Key -eq 'C') { + break + } + } + + $bOut = Receive-Job $backendJob -ErrorAction SilentlyContinue + if ($bOut) { + foreach ($line in $bOut) { + Write-Host '[backend ] ' -NoNewline -ForegroundColor Blue + Write-Host $line + } + } + + $fOut = Receive-Job $frontendJob -ErrorAction SilentlyContinue + if ($fOut) { + foreach ($line in $fOut) { + Write-Host '[frontend] ' -NoNewline -ForegroundColor Green + Write-Host $line + } + } + + if ($backendJob.State -ne 'Running' -or $frontendJob.State -ne 'Running') { + Log-Warn 'one of the processes exited; closing the other...' + break + } + + Start-Sleep -Milliseconds 150 + } +} +finally { + [Console]::TreatControlCAsInput = $prevCtrlC + Cleanup-All +} diff --git a/dev.sh b/dev.sh new file mode 100755 index 0000000..3df61e5 --- /dev/null +++ b/dev.sh @@ -0,0 +1,142 @@ +#!/usr/bin/env bash +# tf-stocks-panel — 一键启动前后端 +# +# 用法: +# ./dev.sh # 默认 backend:3018 frontend:3011 +# BACKEND_PORT=8000 ./dev.sh # 改后端端口 +# FRONTEND_PORT=5173 ./dev.sh # 改前端端口 +# +# Ctrl-C 同时关闭两端。 + +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BACKEND_DIR="$ROOT/backend" +FRONTEND_DIR="$ROOT/frontend" +BACKEND_PORT="${BACKEND_PORT:-3018}" +FRONTEND_PORT="${FRONTEND_PORT:-3011}" + +BLUE='\033[0;34m' +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[0;33m' +GRAY='\033[0;90m' +NC='\033[0m' + +info() { echo -e "${GRAY}[dev]${NC} $*"; } +ok() { echo -e "${GREEN}[dev]${NC} $*"; } +warn() { echo -e "${YELLOW}[dev]${NC} $*"; } +err() { echo -e "${RED}[dev]${NC} $*" >&2; } + +# ===== 1. 依赖检查 ===== +require_cmd() { + local cmd="$1" hint="$2" + if ! command -v "$cmd" >/dev/null 2>&1; then + err "$cmd 未安装" + echo " 安装方式:$hint" + exit 1 + fi +} + +require_cmd uv "curl -LsSf https://astral.sh/uv/install.sh | sh" +require_cmd pnpm "npm i -g pnpm 或 corepack enable && corepack prepare pnpm@9 --activate" + +# ===== 2. 端口占用检查 —— 占用就直接 kill ===== +free_port() { + local name="$1" port="$2" + local pids + pids=$(lsof -nP -tiTCP:"$port" -sTCP:LISTEN 2>/dev/null || true) + if [ -z "$pids" ]; then + return 0 + fi + warn "端口 $port($name)被占用,kill 现有进程 PID: $(echo "$pids" | xargs)" + # 先 TERM + echo "$pids" | xargs kill 2>/dev/null || true + sleep 1 + # 还活着就 KILL + pids=$(lsof -nP -tiTCP:"$port" -sTCP:LISTEN 2>/dev/null || true) + if [ -n "$pids" ]; then + warn "TERM 没杀掉,改用 KILL -9" + echo "$pids" | xargs kill -9 2>/dev/null || true + sleep 1 + fi + # 再确认一次 + pids=$(lsof -nP -tiTCP:"$port" -sTCP:LISTEN 2>/dev/null || true) + if [ -n "$pids" ]; then + err "端口 $port 仍被占用 — kill 失败。请手动处理:lsof -i :$port" + exit 1 + fi + ok "端口 $port 已释放" +} +free_port backend "$BACKEND_PORT" +free_port frontend "$FRONTEND_PORT" + +# ===== 3. 首次依赖安装 ===== +if [ ! -d "$BACKEND_DIR/.venv" ]; then + info "后端首次启动 — 安装 Python 依赖(约 1-2 分钟)..." + ( cd "$BACKEND_DIR" && uv sync ) + ok "后端依赖装好了" +fi + +if [ ! -d "$FRONTEND_DIR/node_modules" ]; then + info "前端首次启动 — 安装 Node 依赖..." + ( cd "$FRONTEND_DIR" && pnpm install ) + ok "前端依赖装好了" +fi + +# ===== 4. 启动 + 日志前缀 ===== +PIDS=() + +cleanup() { + echo + info "关闭服务..." + for pid in "${PIDS[@]:-}"; do + if [ -n "$pid" ]; then + kill "$pid" 2>/dev/null || true + fi + done + # 等子进程退出,避免孤儿 + wait 2>/dev/null || true + ok "已退出" + exit 0 +} +trap cleanup INT TERM + +# 用 awk 加前缀(macOS sed 没有 -u line-buffered,改用 awk + fflush 兼容) +prefix_awk() { + awk -v p="$1" '{ print p $0; fflush() }' +} + +echo +echo -e "${BLUE}╭──────────────────────────────────────────────╮${NC}" +echo -e "${BLUE}│${NC} ${GREEN}tf-stocks-panel${NC} ${BLUE}│${NC}" +echo -e "${BLUE}│${NC} ${BLUE}│${NC}" +echo -e "${BLUE}│${NC} backend ${YELLOW}http://localhost:$BACKEND_PORT${NC} ${BLUE}│${NC}" +echo -e "${BLUE}│${NC} frontend ${YELLOW}http://localhost:$FRONTEND_PORT${NC} ${BLUE}│${NC}" +echo -e "${BLUE}│${NC} ${BLUE}│${NC}" +echo -e "${BLUE}│${NC} Ctrl-C 同时关闭两端 ${BLUE}│${NC}" +echo -e "${BLUE}╰──────────────────────────────────────────────╯${NC}" +echo + +( + cd "$BACKEND_DIR" + uv run uvicorn app.main:app --reload --port "$BACKEND_PORT" 2>&1 \ + | prefix_awk "$(printf "${BLUE}[backend ]${NC} ")" +) & +PIDS+=("$!") + +( + cd "$FRONTEND_DIR" + pnpm dev --port "$FRONTEND_PORT" 2>&1 \ + | prefix_awk "$(printf "${GREEN}[frontend]${NC} ")" +) & +PIDS+=("$!") + +# 等任一退出(bash 4.3+)或全部退出(老 bash) +if wait -n 2>/dev/null; then + warn "其中一个进程退出,正在关闭另一个..." + cleanup +else + # 老 bash 没有 wait -n,退化为 wait 全部 + wait +fi diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..b6c3bbf --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,16 @@ +# Phase 0 单 service:FastAPI 启动后既跑 API 又托管前端 dist。 +# 见 ADR-17 / §8.1。 +services: + app: + build: + context: . + dockerfile: Dockerfile + container_name: TF-Stocks-Panel + ports: + - "${PORT:-3018}:3018" + env_file: + - .env + volumes: + - ./data:/app/data + - ./tiers.yaml:/app/tiers.yaml:ro + restart: unless-stopped diff --git a/docs/screenshots/backtest.png b/docs/screenshots/backtest.png new file mode 100644 index 0000000000000000000000000000000000000000..c4b55c8819881ced1d8be2c9031f965a397acda3 GIT binary patch literal 668676 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%0A>E&W+q@3}C|B;E-dN7p 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

4LH-|5$_Xz`hxL{OVO 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π=5#-9`$=V+6POOi#+(yxC&FXLo>l`Jgy?ID)BP<9x zZ^d@^O9Kvt?RbI7PH=i#VUxj(F5kMSp=@Bv;!0%rXlL&kq=6DQ&3t3^^T2bipbUqv zy|T@!oHuCMWp#BIB;2y0hu|q$bE0heuk4e>3-|~(Gu){Vj9PK^i3iuz*k_50mHSOd z|7>X)={tl2L%Svo6Vqzzr@0Mf=Y!dc*bKoe7|i#nu3{NupRyr(_z-v)90XBiPTSI~ zV`O)DwIXHwz=CtjK4j(>6n&mfldl3L<=byi#iujaP*+_hX6jh3_5b{L(+e~JG}VH*q*1`mjGRNoO!XNt;&{&`pacLwCs~@cdLHUG1S&ta&`_whl%>Ae9=q% z@miCJN5s1D_E0tNjoxF0;6yR{gCsQ>B1O+R-_3&_V`j(4#K*7LJy&tdn;pWsHh^Sni9v=YFN@UR!whgBM{vJ;hXH&@7|_#$yD-!5YfFj3 zNfw=IpP6!8K*b!@*v=)?*7B|`PE1T(Ung)U)BbIlo_?C)xJzg(e)QB+a`;@;*y!!v z{jsLzDoUg%=8rUt=zBGIh^mZWIQ}cKz*sG8innc{pEjeTV=Hzc6!5T*gMg6J9Z~8o z&elOkj-$p)acgm zdOt9iLgeXTX!VB*V_ZM8BE9wxFEpm0a!i74ptii9EYuhuOU<~+)^FrDE?eK7v{opYF@lAA zfT7@sonMScMN`sY$foyD`dOW1+%8R8ur1nd0ZB8e)YLyl%Wh;D2a06)*OW^4wj#8$ z%pVLfson~bE3jQ7Xtn`g63JivxPkzb$4t%>^*c0@rub<^+ z{{H_6`wE~c*S6h-fFLQ|DF`e|k?saTy1To(B$Sj?>6R{O>23sN(IH*Z-F+VR{=Rem zIdf*t9%ehv-U{n|pSbVqz9Q`f0nc=LUjdaEM!RNV!FZJsA#78&a-+(AYjN8{pCEFl zbE>b!F%ON0XhtfTnz23hcMm7~;ApOpfWf+lPmk+c|NOL;>qT`PcM&4(#PBV8f8XHL zhY56VxkGoPq?Vt{(fym-Z+>e=?vGk8|1Q7YK1&xP2a62fp_a;o(4} z_pK#Lzu7Z+Pu}U_-k0v>!K-Cp6(Q+?5;Powe*H#HTDpB7*Sf|Vmf?#^z``DK<$KQ5 zBo;c<;@txB*KYv@8Zr$KIp=NiEG9spk0g7uo%+E13>mG{MS?e-MS$6NvLF)|S5q(1 zJg4>urk%u3!PQWxHwOA15wFI70qdrND9quE5a*+xMeg9wsCUxKIk()m&egm#Qs8yi9^j0*&`}2WH-*)`@!tyyv>yDDrv+d z3LX_Q*W|OY^WgjTJp(i`y~+J-Yo6~l!&ch^OB$btNCD$LH*hw-UDq&ZsINyOW-oLr zQE$6%Y)}T~)eENPg0oE?20Uth8$&J5#WO}>FC_3jz||KhI#t@*^qW?)3|d>F;EaZ| zTPd=Tqj?ek4eyQKnsvo<%B93rY10>TpeVVIdx@&CyE0jt>ankx@#_5O96Wjih|SZ9 z(~AsoYNeuZZbJ2Ez)tWj29s#i2k`5z%}ZsZ5P~q{p!c;t2ikYM}dhBciJc0Q?FMHSwG`_ zTNn(lXf+~qu=WtC$3(tLdrv&HFy(t)kdm$`0?o&eBOu9Ei3?Mk&cg7|qUs6x!g^tO zFJE!kG)I`evdR4NjA!aHWN+sr`<7nJ6@>$G**Ln00rs_u42SDgCN|_g%h+^iTs4YG6w&dE=Zm$%vS(yKoz0u-YRr3xTH4`L8x!lznc z@*i@NRjW5~@rnKsPGa=h7b}EYyoPZ^53p zpFJlT^;jSpEnn1u9RB8#1(1ztSCv!@7m$0w0V0i`&+B``=!0)z?(&~*#lPa8+J zQ+){ofB(&t!7RXJEyy*er62Ac&bB99E)OwzGI=|2k?_Cp3C}m4x$^$)fZu4g14+af z5biwA4*`pXN@L^WeOg+{oWCqnF2HzyY;4Rnm4`q`sBL;$TT4qThTKUzTZ$evPqKg> zQ`$A04I391e7OQ6hBTzyNNy*?Wx-9JIwcn5;7-XXVsN?U=86~Sa(zUv7cX$+{pWxy zjJ{Q8Z4Pcy4OPsMy+|jw`zTx}o&PRbyH4L1C$BA&0)x)|_HrbiQG>f>1Tc=GNqHm- z#?B5Fr?%oXsFjo|y}YUh_Jhgln|#y`cREr;CSv48<`|F>MC0?1=Nah53Lz!?xWY;y zKhXQ%{X4L*9G)`QgXul~1|#9$abmn&7#-P)#5%69vU^X9TIAWPSCeQXTHXe)pOPo; z_iN$izd?VUtE^yNxZ+pG{CXnY1)jKvUhO#|CGbi=A!=O8$!K1mFv1YW|9qi_^sBT7 z$TUWxbzWd54XWsB&wD6+@8M36rnX|$_u|u2pWS#-Q=3;CTM=Gur zbYwdUnSS3811>EWDkeY9%&Ij6(~?)4+5gW<&Jj{asTtvfqc%oi+(D2?t4_Ews7&o6ImWHr((4Q3J|oB{Zt&)Nz7 z^R3>$y}y147KT7PJQl;rG$2&{gD)NjJz3XIT&-oFKbFEwt0~md4%j{@zD5I9$bNT7 z5aA4dhtBRw`54Kk5CGNeE!@eOWjXir1*YkH(RPlccTPvR`PRYsMC8-O5+LDTU3pCwYqxmM1Iq*T@0UZB7&sm%eTCQixHL0J;Ld|g zr^f}@MLo}kP?72{{Qt*HzFu)w4ZN5H83l~%<=NH8uJXl1nSo|4nSAS8C|A(9jED_j zAnsaq&uwc^tRFF4h%P}}PI=cS#x)Ax+{AE zoKoNn9LgTa^WlfMnRx^XJMvQaaaU=S3qn4pGNy7n*@}E1^D?bp-5`KKyby;x#tZSo z#Hl|hZfP0hAo=rRf&;|G= zl9q;EGK%It--Y4O+ZAyUk!Pq9O@402lYy!tJTRl_ozrll%GDZTF~K{DYegtJvj(-r z__N7Va%|{8=+l64f-tw%_OA>`r?d_W+srQvS=Xz+Z?KT0$qnd)K)r04m*>~Rc9!GpI9#3ZTfNK-r$`uY4eBZ^fY3(P!DHwRLMOMT8 z_hIB2k92i%e~4Or4G}&6dHtz*Wz@^ta0{+}fE6jPmzG{JOA4m+gB5R8fzJH3mqdSv zua-~t$4yuux(2&6Q=u8YS2LWCK za(uWv?S?ErmYT@HTl(CIqBXoR{13u~Oykyh!Za&N&EZz^p{~|7RmOj)!LtIB)>II@ z>Ap3J4yj^$LnlvcP{tAiXf=>S=a+}0)-`O&zl11-bJPb-d4O;3{_^(Umx+V%!6*<= zLIFbraClr!MeXCB?Qm?4Z7@gRdHdWX9Y9s-!}xjz(VQM{+aNYkr8ugyCsi6xRRkvE z=u5YcR;>RwF!g%q>)_Vd3Z)Rt0)d_EuiOO6HwrlG(m56xj$=WGgT@tU9XjZ0%*X$ zS7(k#Y$uB4O4RMX@BJS5Mf%2FRf|`VW_<0h6Zd)^Q#z@uf=Oqw1hrmHQQ_JwAg}gpg9lOrO^o+G~nhJS9pKM(A zizuw~&Yn+HjQg`f)eN4oIZI2Do~r4aC#s*dkBTLqnSa*keLM>sF#z6-%a130H^?E0 z82p2{=S_Nw={4nZeH3&vLOkAF6$U)wsK(nA@F2mTTOu_6M8m{y-0`to zK8+hBdOL^iWYI^I_aJ+N#EYp~J3bd*N9q2$MV2>8Y-qrP+oF;@UERWtU^y?iUgdEY z5_ODF4pje`MA3oivFNtAmn$QT$l)uoXUR{T5?ctM4elr05MRP5Othg}l0u-Cs%{U-Wv z4QluErJ1{6j-tvJ!8mZ+P_5@}WHa$}QKBZ~N!fm*noh?!&Ar53D^c7=jVl+$!(n}5 z0-mt6I0VW+43H_%riJUI|JTc^c~&wKCZyxE)glVwSG)!fyGprLlV8iLbJpi zgTDD?QBe$I6XxUj6TiK5ECEgk0eH4pEJal-??5zmh)OtMHierQsU3WatkeJ>2-Ce> zut3v0Ja!?$Rv*83IK6&^t>w7~1_>Jy2ErN}554D_j8{{xgf% zR>M2INP-T%rx@4U(JtwqtW7@^vDx!-oXOMtv&!=4)HVba<%?Vz(Y{m3uxXJgj5_#S}bT5vnR1$k_`q2rXnUk5baK+)-IBITuC zBP$8RMIo@$t_4N}B%pNYi9SOVhPT8T_$(%wAz#8V83~hnV6{hup(IMcpl26!U&vy= ztg_9L2$yq3a4IcaJF|WO_b(dhDJRtks9yhl{r~wzEpd0(7CZ)FN=N&e)n0i7NV+_z zuoi%VhDopS*Vx!jY25_~JWDZb`^pX7S?#|>f$(s*=rN!68c@d$C*J@)w_jxKH{ zvlgb0{}=+U7#552R`j0#ImN5Z<*r=FLx6mGV;Z*?HRGFVHu+%1^?!LkiqMd^lV7)9 ze)fBUDP{jn6N{4j=elN!^^P;^|ud_?!|5T(u1}{>&os>(UdzUBaOU zaYzmH&o*S8RXi-QwXG9sdXX6Bf&A9u$jFqs4(8dvLJgP=l0+y!IPF@*z50Av~20(7~pI)~RAOn-fzCP-Jd{1`~1!6AA?oB?{!|s62*TU~=uSH!3xf zm?Oa`iB`7lH5BxH807qie^Uh#-&dce(i#Z)UjKNa5T=Mn^$#};Vuy6uz zYpMPdQkSvHgp@qVgd}H|u`IMH*icN=|5*b6JOD>*z;PvhW6lq8-5L$vlUHhTPfM)h zf|zn!8S6vi?=QPxVA~Xo`EuTjef%i;U4tHX(f8u_ujFdI`8jo_2cv<$Sb#gIXn(H) zP>6gH6JT~EO4ERY5AlhSxTpANmpB9&8SP0xiAK3L|L6RzN|Qb=yFZaeN$4b#>wgEP zeSkU5{tEThaMsxERfPNA99S&ycy6LW#bKqFYme`!9gbF}QWyd_)pP^US(Oz{+@Y^L z3H>3Ugy;{^wUb>_Z6HoiL_Eb~4ip2|iv|)={pN?f4{STXD|i$W1tb5dgZ{_IHp~0= z?Uh0X5~Q`&PpDjbzSgd(zMl60!`Iau*6S)b$>bfxpw2}4(PGZ z7eG)0sgNHoL{wC4^1D7A5F;%ZtNmSQ;RDl@LXA3mFl+<1H&}$v35oFBPX7L8*10dl zQ;9H20`u>`Qb4@pTW4zqfMt~U;FG_;e)qRLE~$%tv$s3tBn;u(LWWCe4JSdOO2KK* zv!J4n?e>!_*UwSR-vU@RMztB2K7+%-xmfpwEPyIGm^$DDD%cgx1;)jR(x8EF%nFUY z{~x)sdPz?$}MnlQqb^G&hUuW9hE&_B7kTU(I#;ZCxv+r#{X#if1i-!wRfPw!! z@L5K5Nd?fr?Fq~Xa(H~M-(>FVXemuZQo8akQ&5E-dvE$aQM>ed??Mha>)9$Da0OLk z!YU}pBl~qmLf|w3|lhJR!ff?ah%Fz~DVr zUSlY^mNAfg-Ulct3UYHvd2hKO{D63Ix}^dX0TgU&WDw0JV3z$W{Y1ji@s$B3Bw#Hr z6jEV55d&(f#TpxnqBA;L+TST0V$k?vRS7(2u)vZ3sgGIT>|U*}*u4qFPJJ3bLhvP< zUKm#q`T74h2YA>Y-Hm#;jiz-0#QBe^~7gGZAseD}6SHq%= z1{MzL#~xN3N%Ofe`u}}<(68UW|9Xbg2b@GzO%)X#MLW+ve(YqMJ8WfH3!GUITZ=#cmI2SAjgn8^lS!%;u_nL?UJ4d`^8qh-V9X^dm0*chx_Z%yhTC| zFxXHn3O_zUF*Y`FTKkk*hpnqigBEDNAOnb5f&kj%!S`kOpD+YW1xNbxyh`>CR+4wSajzh;B9$`Tx>%ea{$mt0H&>wgzu28Iad7d!Z>RxE6nqb6t*X;mhc?83 ze7RII?h2SB?XLV}sg46s4Fla5yWA?588A-qy4j-wzf_i(xO4mg&?)dOK0iEcPbH4} z3wlKOr)aJNbN=Y7b8Qwt3|YE&cXz>@`JQb;{E@S;_eV`I(|>2ObSS+kt`eS8vKmBE zf|_)GMQOgV1sHlnv2oswQpd}HpNxz^LyB^^Ej#X~DFDU%Q;BXsp!oBWvAn03FT}`%0a$!^qg2iU*9@e+EK5+s6!|?F_@VBB`PA)F7(z+P} zgT=ei;OZAer{duO8tNVfH3_M{Lr?yo;rlzEsd9t9qe5W$k|F5py+D8pJi&6y%JlUY zENB== z0R}bO_C|g^1!2OGa&136y}Z(ST>eZ=O^E}oTf%ae6e*AMG|QW4N22_C|32U(&|o*q zc}~HXlAn{E1I9*EU{OX!zH7Sf^-a3IT#W(F>+;y1IHY2f&%=6*KSgSVQ@q5XF?d+1>rp;VY5m-UiVLW?A5Fw$JtZ*>jJ;WNuGz3bH8S4CGexDC%?Xa>+NoGEO6mu-?tmdcIyf$*KfF8j4w%yyaSiu z9f&Ss*5TwCChgEqU^Souff>{qFSxQuQN7|Rlhk& zz(?NN`cI(}1<-LOW*370@Tbn9O^=GmlmG7E0Jt8^m`;IQk9X`vMMc2D_Lcql))*2} zkSD0QCT(Yqkuq|dfgi(4kHHxG+0{noREY+xr)Ryq?LIQbKi#LVo~zMuS(Ja#Yil%* z!)CJ9cEc{s!=x%f>xo0MOnhYo3FlKZs?A zQ~*f z96%>zWnzlV-;#*HC%mKKPI2lkGb$cGxV%^_?{3B2+S&r&{p|GA`)02LWc^M|oB_Xw zJAl}@pGB>{0_S)FcqArTB@=&!WJL?TT=zx=*r2_-{!0ffTSe-6@Itqa&6$}L5+j_= zj^oy9=hffi=zhLzyZwE1dP>Z0S=ewtQ~hhcsg8uJfj`6XeUK3j4w>v2f0QITfc-M_ ztpIluFw0)n)`m9GiC)w3hi3;-!+}C3X^C~^cLdt;$_d2qHjq6z-}BeTSVe<f>yC!8Kj^UPXCDP$ZqtV-p-Fztt@hNr{{ zwsHpHyFu8iObzcH?Qerpw0SSIThQX>$@)@Sd*hOvoyU|m_)YaXzkXeaKsQ*k-rzQZ z`yxFKUYVeQ1nY}-F*mpNu5=qg@gM5zD7nWK_SB_$rKqDM$ES6+w6`G>Fmq_Urz!*UhFYqq!E(n z*etbsM3vh(349QtYI3))-ib@)uv@6nQCQ87sWZqFgclR*#Gn{yLq55kk zu;T*Pu^v4xh(w>?x2!B!Dk@T9{QdGZZL~zg0WuAa8o;3Evem?V%pU};F}?_L zrBvihwGfDUkZdylO?VX{CZ4L#FfoOkR_axuzDFw( zJCk4-vXO1pGdR_ku#~?Bn`xqNh3D&D=+yT-`1$8A23` zR6*bSl&k_36MgjKI@ft%ENn3au_qjfbC$#r6ZOc&{FlB5z7f{w^D5<<)WQ0T{kM^LSKJ6%baDu`snYFx+9Uj z@=8>fT!CA#GbuJXxz(u48e+NF>N1#M7v&vd)Oznto&cuTaD8J`&HO*k;_g-XRE<5q z;*HVj8$1iJ-Z$q!(+LQJ&8KI#gqBp|MMz)$=&9wux|TYVU)UESxnCQv%DQNBS)# zp)e$_CX$?X7ws)VVdp98*UvA*vH+-$8%?M8awY?t&|-j879p(aW#BwpSw|J<%K7(p zm_T3NV^A}70p|o1#b}?rU$gIQND@v5-#4G{Y&m}zJ7uT zRT~j{NGgL`PO=L!@jsz*-M`(6c(@}WBAU+|Of4(32WbL&HP(o=TlbO&y>cmV!sdU+ z+S?5y+W<^cHx}v%m?@;7w3#R+mSM>>c4I~<3iMKO7ti^ z8LVG6L8I@a{Ao0MQpgZm__SLe;k|sVf8{ni8#s}u)p!q z5uRjJ|Mdh#IjB$>!nGS+8FVt^;#5JE9~S1=^a~l|n<70h({?^u$+H?0thA)WMLE=6 zsH6M&Dl#`9Ul-RVUk2-m`9w8!1~je}%0DCUY)pXPdu*s@4kv_ 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 CS3#x# literal 0 HcmV?d00001 diff --git a/docs/screenshots/dashboard.png b/docs/screenshots/dashboard.png new file mode 100644 index 0000000000000000000000000000000000000000..7d4af68ba29685acb62fce489905a496a07fc572 GIT binary patch literal 641420 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≪GK-2 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

vS!v=rDNwhrywHZKOHAV9>L#Ie*^ zltuF=rn>2{h%N3Q|Guo!nIeFm?_E7xVgMr~?8M$B$GTED(%)T8Iy+u`a}LX>F5mh3 zbp?d#Y7c1^_4P_kyBgQcQ4*EBe#jT-l@yHiLHmEgO9BJIfDJ(N;S0?=wYPrp1VIC3 z)SRCS#*zUsB=~ZAGnp}aXk}MHt`C9+Gy!9mlSv@V>OoLe%;Qc+x0c<@!f!oX$>Wqh z*YHltW)~NBjH89yrcILZp`n9}+lJp&y*;mbdg_=fu1;rcYG$xPmJ3USO>Dwa`kp$! zz#e@hpZeQ{FBS0L(kqd`^d3RPK)kWr($NLv(e*Qcz^s>%diryBlB8`=bEg#q-huSS zEYcoWM#)K-Cveqc<l;uPq2aC*V$mn7xm9rT4Y+1DjH9g2G(+~%# z7GZfn1NwN|&W1E1cP%&A>*^2>FBS|cm*d5#31xv&xw-kb-)p_MKXqyp1qECPpo*$0 zzO>V@uyRlv1926?M~_U(--d^?!u%c*QrOr`jE$z6@HAhX%2t(`k2yHkXXoaAD=W*) zENlAq?H<$wzwGt(6#)$h)H!?9`G@bw(kE&ZHg6hy&rc0(9{95(i1_SFI$R_y@;5(x zDM#fxoKlGMYfPCQntUjj%90q~yK2u%D{70XHG@d)_y(hm4MT1uu6Ok(r|sXs%=uYD zLP93zeWvuvShML;?8b<3sa0$I1Gf*qfScbD;~N}ZDm@P{od)E48&Zr8Kvx6vO88kb z%iA9UFJ8EvNKux!AKH~)7+=aGP#>qTVU&AajrZR$Gc)`7earBkUfVr5JIfIC@ar~3 zg0hEf1?b^V(nXP3(hhOy0XGeWTBGe+o= zE|yi1>AX{qezAR&4~eJq7M8Q<1rosgXFQyv&oP!SPGb|2)8hsGi-_JS+BRhU**)}N7;AjDVMfVq;G88-Mfsj4sLi)Z-J4yU z96#?k&y+N;xt;W`pa<)x%JV}jt2+Q=|5{-H$+ywNrM|iTDe9m8+Hi>KvEYn_i$4|6 zdTQV&Do-h3*x03(4KV@^d2pW)&;p3+)#yAyBa(`6Snn?t)Uv~2P(kqR^?aW35ym0$ z{C&KNN55jlxX)}jq-P<}I>=IgNiZNBNr&yS?%ifXezTj*K+pmo|KrGqklN@Y^f#b^ zmqF;{(!!=R2`2$7+@x8HI`P>`+A<Ht-QNdUUG=;)Ddr@*w*X-ml7Ci!(o@u_%q z*4i2{OcvVTy#5pJv|H6@?7-^js|c$o0v)p5Rc_+o)@mZoLB+W8A~~Oeo%h5q^UmZ8 zUbr1TQ2jrC4BOp}<4rA= z(q^H{1r#f5+^P;w{dQBcKQu>Ea>ZDftxF8-lt@rwrk|ZN1hp=qy!Nb5ug8do9!VzX8ZTXPjRu+x{ZCM{s;ZKU=IHbo1Pe=Ic~Mc{mLkEb`%)0hV=3+*@MWDD(*2N^Qk{$h_DQN> zDu#n}(2hS)Dh}EX9KdN*9fHJltu`)x|JDN1nd`n<#el;cQ&RGyNUqszL>)+5k??VP zAN*OpkG1lUfb2e$oLeVw51d7aoI9Hvp)`SmBCQV@Uid%jF~_6L=!>>J8{xJ(a(Qqs zui+Q=t0m-iM94_Fn%t{Rx%`v%Px15%-|X5h)hfRTm#Q};^4|26RT2c;!v#Xw!l%vf z&r_Ip&1G=8uCEGA-!sv1p{m+riL&*fY`zXZnPAMrB6|EksPTMO;QO7EV^qh(&|?Iu zOwEXw*~KL#h`uXdkIR-jR0y6B%0geNnr1qav$I1`k^DP?FS|Z`C>XJ(L;bTo6{}tE z{hk=~llM5-e{@D=2mtkkypgwBT9fKW;;5Mjd0cyMyF5;l^;M-Tj<9=C{Z}sA>wZUk zJUT4GH@Ui)9_!XQ*g@W_CTbX1x*Ci;)#2UJ3Hb+!;uLEqj^twWyoC)(lnnz@B;PQV zs@Akeaj8Qk7ZG-Kh4eqbSkh~t_`*aOu2W(&vUO~A*}qD8Y^CW>RijlrW?lrQWZxDI zVF8M9z0>+dg@qi%)7WI!@%BmttCw6h3NmIf{JEw3hT(OqRWrtkiHX`bal~IdOzlD8 zHex{BGo@yCbHHN;3Jx4mQT-b)EPzW2+TZVTfW5NWr?Rt?sjPIpeWV>>sl~Kc{2J2p zrDkDvTc4`35iok8I93AtfFqVD`4X%4z=zTxq<2$+-(&qFSe{HcQF?zNpK)Dl!1eAx z6tIg$(Iv$sWl3D#L~yO7;%U$vw6X7dkSogrzbKPx(t3z0!Q&d}O-m5Q(6j0YPjB`C zi`*PFXWbYx=drS-(vP_t1wMAJ!SxkdEoXo+akBPAv_4<8o9u|&D;b{*hJPx9zo%)w z!jvWXXJOF&sHXY{ZLx)?@Bx{s_$1_UI?l|3N!Z`V<-afPIwD?oRn2cA?a1_(l+g(O9)cc|Xprqlh;x48Q%n~0z9@Yw6) zl59{51YwFGMkh|U=RgDAe@~nLzHrto{pIE2K+wgbtN&U1zt1&Qz?;8Fwx6cS)TsUl z!H~ax@$l{*zU1G_{qIX7R^i|4h{r`jOjJAGzn+p5{(pTV(%FB(l;Ot2QNlVY>c?ki zN&hleQPBJs9nbQ5U9l8sFkU~d@wWzJ#QmJPMjSoK##VnSx1YWQ#a*|Wc3S!(=nSgP zJo4x_b@L@x&v52Gy5hyR2q#gMRBVk z0IoaW5zES5dupzomyDfFacn%dd}b$2%7`5~V*msc?Oj>WkYW2w<^Ok;6m^%v5Fe}U z?%99%L24mPzB{%2=|Jl3FkZUA=Q+nJZMO7_pNcRM5Ulm00 zZDQ4&VW!^{&|3!Pc&6~}UCgKAY&s3EGYGY1tX%ynO^F*b6{?nVS$SADsp@T%XWNs*hr4DUmqry$69zxDmtI{>^*(!Xf30Z1{OfMOzOR8sdl;p(iGElA&Oi z{OHQrJD(0$OLVba{a1{^2ic@I@>V&!tkWIkD;My03QsLUBPLLP1e;rAiO@W zPKCpyRVu(F05Z=@b1y3^Ct*2&tG)Z^QLfwPtX(RJZm0X6*>TJ8s1=#xAPcC)=eI*F z^$7I0n879Z0VM8_@+2{#u&+5;rMMs4X5H6wyi=e}w8Kn?>%6ATDe2)6$(cbxZAwawW zG3IL?(4hCR-0zH<0=x6!!P-Y|aB)F?@FGrRWqoa3tF7I2y6LvNABGd~&XAAuhD0@MTMC1S2Hi zO$@kdZK7lfoN9y8KZM}8dPf?CfF&M1VU8^VN=OP^5(9P;pqDZ`I+-7R#iU*5PfjB< z|1+ppCib0@lA5Zj$jE3QnhFg~*5puhbg2}D8y}N^e=Y+=RiZhG|L;u=FwHBtSx-s# zNuBNq7bmRbe@!MhmL{xUFkc8JQae9?q2miZ&cH)4v2(@a_Q^6E$x4n=ZZSfJL~XI4 zeFEGbJ66coz0;tgZI-fJLNH(vef9!h-pc45e1@FsYEn+=x1o~l)0wBp=q~U;742_x zXV@c2HY7a=P}YZ`rX*}cUz!sNsFa6r^t=2Br8{tMUNV@{zSjW{h&$&W%enkndGlO$ z)Zm((()frDq+SdQJ2{jPZ z9)mx59hw|fPTEv=XB?#Gj7GdM$WQzHQ>&5H&FTg`m9cJ04?z`dt_d68>q5VO&aXP@ zF9^O!D8!In@i2vNmce@jy}3H>%{FEDcZ?h;KhY`1NC;Oad7hMoT z#9_kW4Z@U=t6wOR%#Xr4)W;p=`kNVWJsa?8RcrpyK?^^+@h|ah9D;{NF@&rj%ey^C^;VK6QgIWfoR~EMjX7krviQd%L1DF{`)09RP&(P zo|i0dq}$lEs1KG#JNa zog_8IvJguU6k+%%_^@bKUgcsfJUjF86e%JEdO8S@Ivy&7v2)nx)Sz?FF$0S;FBi{Ux5;`u)AbNGR!IGOi>`SW-yyAUVNw6EV^MtQ)Tp~YAJv%+R! zPlH~KRq#Mxoc0z{DI^sK`@&drzQ4?a3#0(fSlry=U>qWZLsrar{C+a$52w8Bvl-jB znv*EY6%e#qfdEMXyq0o)Lk-amYVv^)4w>u)cW+Rm7yom|k!<=2sGuhjN6geW+blRs z>&A=F_n+N3Y#J4-h=llBy_em2Vqs7I|K@A>XJx5uN2?V+Cyh8bkePb>*vY*Qw1SC) zfh4b<)Y0kg_5}XF*`^GVhYgFP zH4$Y1{?o{u#)whRG_m%V&(CH^q{MVu3;_g~tk?T9mCRYbwnMO07apvh-v}*yGPtma6m0VJEGErjn%Be$y^4{i z_>?HGJ(IMr+KTxns>?;af);x|C6@O^)*)K9x_ALXU#Vp^V*C!>D>}NDau>#V_(73mK>+B+|I7)Dg76{AD3P zpFX6`uktQYa|+2N0pLXuwS#pSBf-YTol(x#gwIeE>`swN?Ii~WTMMLh1cSaRp3A3k zk2EI5Ccn}2t}4h(nETyF&YZ|Fn+;^3Za4CZI0Y5GZ~sxvSSNJ(l^B53Nq6=yiU@GThq&HHag7~x1PU!JIAy*Ypn;!P@kopM|t_t zVLNXQRHu1Lk)=Km$gG6pv<-UkQF4AzjC-J`H%BWD4tTz;YJ#wb&vuO;0nc`@GxHSA z98fG=UC*T`8~1E^;d{66x61a786-fOpw41~6=3TMeP(OQI86EloSA&K#wnpiScVUh zuVi>aa^L51Ft0{L_1btWjIhY^WK!EhWXZN`F*^Fx*~`rh4Kf|=10wh`G6mGsnR0Rw zBpYu5YjZ%}d9@UD4-=xnQpSb-r+>T1uok6?jqfO zpQ|DnS5n?bJCaQ_tSDyTL8Z!>v7t>jdT@_YFZrN~jB_^EewZaOq`~NtelRP)zY9v71?}^rrWj9OybMbXucAuGAxjMnfkny+q4JZ1A**Bie#Cc^& z&eK`98eQ{7d3~gP^DsWrqbpna{OV}2=F*^dyu%`p?Rw!@efmDxNuTSWOFKT`77Dn=W|0@_o$39PyRTHOhjOGn&gp;16k z(CKvh?e{C;1?4-GqsN$;paAwMVQCH^$=g$_-jPD@WI4?X9dV7Z0S~gCe``SE`lg;+f!i)XU zXuY%_jU$}r>uY2Pz+xIstf$RRFrqsK5Fowv;1ZK5r-$5fN;e%dESP;qA6NEsL^T^Pticc{LX*;gIwn9It8)WZ9SsRUE$5AEaY$1G3B3_aUo!2WEbXALHamP!nVA*_!`l zuz;PP{k8B^)ozPya4e>J6bPvw8ojJ7c&&@)S6{R*g{pEaAo`wW+n`_nnZ!fxo1rwF zheMFY)!si_r~Q`%m&37skmMajGe_QQyxICqoJ8ase^rI=b}!NiQf7Cio7qM$Q> zXXM7C;}O&gyS*4tsMi_=`eIXAq}v>=4r{Z|Eyj0t&jDR_T8$WC=nx7XKl{ys7|VuAsb(Nv)sm=L#IS*GFR8HR{@jb}e| zh34Fd-u@I2RYdm?uV^%lfZ-_Mwi41Q?s@w=eO{P!~GGg3pqz_5;MuS6#s!QfW()%6au2`IpC*eM|B8)#>5)*RT->M4JZd(2HV#6!TndrvssaS8=Ay?>x;d(NJ2k2<4Z>uM=3d9uBiIZCyLbfOflx&g2(gybVM4uG zsHmtb_Vu6nMRBxG5q-5-_GaJe=-4eFVi&(XiV>l5-K{l|Pvr%0o8L(slS&1uYa~pc zw96O>mTi(i=-xxo@e18qvwtCc`yMky9LP>4_ZipEt-Wvu>EcxR6TDC`b*-x2B96+N z61v)6hVw31*p^8D`E~UB1(|Ze@x+EB=T2RZ9kJFn$=`j1sY>n?^7Wt`p~dFdL12N{ z!y<|El-pbH9%xU`aLqFid>!ocxfY&u-kKNY7+t-ZL26a%yTow{ys&SC5 ztu4*}J#yRuglj5Z>LVT(RZnaYX?!B6RUe;q5}>>!R)tp=pfB?`CW&vb1)f7Vv>DGH z1b0`SKXKxOF6r)`Y=VXk@p{z(SAvSY2TG8y&cf-mg^d=6Wp}J3 za2lVB0CoaG@bgc5jc4P)rsKQXOfPG5*HeAV>576jd%LvShtKv7HW8r8x}16gkb`eN zLUL%l-P+^WA(T_$)2`Ni2Ow&Il3s0c%rAJ*?jV-wVxKu>>Au%^TiT5;oA@2|L6jZ` zv*YFXz(mPO4=ITBfJV4{giPsuE*y~AXrn;+ccn77-WSXpS!hsU^gfYp5->`FMLXX% z3vkeCfI|9Lagm--_1w5;k3$!a%fkiMj=QqaD`KaNi!1>nt$^%Sq4~Lw(HXmr#n64u zXuGc7h1pn|S|+!Rhixo{>gYiNb_fdb039P!#Hz9LLIOP=VPqc3cf8TZL30!u9I{nK z69FZ~t;X+pA)bsItk2fvV?!;SOFB9f((I!iW%5$*Dz&vyq08%u0Anuw$LHp+_% zlaC-aK@buy=du?SZ^EHf!UH#Gk)4~3+$wOA=g;n3%b1~(OPSWiv}Y!Ke97Ps4_9#0bQY;jHd(s#i``rB)TNs= z#!{<(g3CpFTAb)Oj5$|zn&qq9UVosuLC}{*5r4rHFT4@eJo4a^h}ZhJ!qS?;7tW)U z*4NHDE$!-4ngo`4*(a%|gUyoy%o%a30&nn)hRm_9+ZsKVv7cT4pnQm(bPuUh)1`Fh z{Hjrav$upq#52po{^fmB44G)e|wnNd}8MpwgCLD zH?H=o`+*V6n7Z!Ho&ykFaMZ5BP@FixKS2Pf?KbR`snZX*27mtG^}ZS?U3~(e?BrOT z_bD5?BZV$jbg!?kWn!hYFMmuf2(t+a_AZs~P2D)$_T7yEzzJ$$K>zKerFpTXxrRnq z8Sjs2p)E|rwXE<#p|JF}yR=L35zY>q8Fu4W!DGA-)-3XI78eN~+{8CCbI5}vI~C*K z<+rRWHemPpT{Kx%-mC%qif|V*BdRODSaV-z9m2EyLgjSx%v;$;fQvyae93&r>*- z9yWX55J^h@0yXLGoS>{4*uJMP(IxftT9%`P-TO-0+t2#}%%78n=688s!!?=Q2+-xc zIz`*7h3)p&3+%Uek&`D1Hz^aG06lm3yaQ-}j3Sx_Q$wb{7I2A1AO|bgp3|udQ9ZNZ zg~<4wQGtM#DB!IFaMP}mldP`h(z%5m-Oc?$A&kH4#Y@_gc1;Gcp# z`1ybjTpTq3*fG2GzZi-sH&IDjrX_P@(o$ACrUAn7F1vk#GiPflHUR2h+6A0!CcP$JB{zIdg2}kp{mmBiJF*c^^Vj;ltW-(D^9WMw^v~g`iwas zP9C1U$+EGsc>PH~6vWOc@&kO3AdPGsM?`c?eg;;S`yW4!R*9m`|76=Xh`Ldti7D2- zwSl2Oe*QcFSW~j#g(CREE`VJwnV`GKq+>7hgHN$9Ysp}%i5bXu8~5*ZQTx0^l|>yn z9l{0wbVHaEr=0Gr8TIu%O4yLQLEfuhsW%($z8woTt>J8?5JCHCw+J6n~iR0qp zg%7)ywXr-7yXk;f-RdylpV^=Hc*Jt%lRL8EbGgv(vfyRY zpZbWx=en$;qoaPeuD*Hz=-4U_;J%vGq8R`nbKuyjRtTIA>vzUiR)zpC)_qTH?&`Or=JQ(-E9W`ov+!@1pd0b6CIv?OmMQ_ zwDqp5ZRzeH8Bq|1K;AGsRbD`j2~hD!zF+|c+7&QJ32F^GPgz3HVsPfTZ03s~z3Q1q zq#v!S%Ni_Fh9ohSQyEoM zkJx$ei|H$~w{HtN^L*krIIJNkN14n0w+8f?(`>rRO4r1sdM)>IF`#<4_AK*}b;DGd zd6`D43lBHQ<~_J;O;I=x=xr z8X!$2UiEwi-I2F7URW zj%{?@5H$$4_PUxjh93Qv4#D!WlqE+U*&=gqnPNqk{28z zMo)IaudFh{N0N}7Tm_80qa>B$;^T#Gj*qmlfN051dno>_u%&CwQoK5xrJ=>9=|ZjE zKupXLQhXbFCI;?p;T)wZOLb0;a)DYQ@SAaLI@wxlYVuX?K~(f*NrcnrX)@KnC&(e7 z-xu+VeI`q_9TtNiB6oGvAlP^M{38JNj$2n78RgVl;<1aFaq>mHgsp$4XJuyWfw^4; zW7-sHxmC;OO_(|g48Ycmy{>j9C^F!0fVcug#k}*{de;r&wKu%YA7Wt4;bUWQxgY!= zEP&$Js38VAdJ>=0OF64CI?867>KVYbij9s|ReI}v{n=t$`puhPwH2e!8J1~&K7Jku z?vH0iw5J#&HZ6ulrRK*Dlzw9(8Cu3lwQOu93nxscN@D5%o_8y~0t8|)sj0M_sfDiJ zL5mAmI|>RmT1`d9JpROAa5nVryP5~^c}i?cPDz;)UYoA80Mm*9ePZZ*yPWk$xkI4$ zQb(p(=4UR8mwI}@MF$0{aeaPEnhVe<6BF7Ndz3irgSDNeoK07|g<|gtR7-TcqF&|T z0UcU<;8&xG`nAU3Ak8jdd4^)2^47I~B8#3_5Av=3*6Fk%)qV+e9}bBu+52@nC&aF1 z7m=)1k$xhAP2r|j-!4-QRMv0k-ntijBA3g}#e6hxNUT;gK0fwFw;Ihk;D1i7_*VsL z1#xn69ZHWop_W~3;h7z7=uQM97)$Q;YiT?&dceGD9W~^0+x$>!034Sf>95LrX_z2! zEv`jU;2c$d+sCY2@X<)J<5JVWtLRmBo5(-Z4)AE9QZK-U#3(j4NW=i8X{QSG}v3BZGT7{ zBo-5sG(9|w0kwrhLB4#O)n|P6s%R~t%HZQkB}5h9P5Zt~ zlW2B2)Q^|rN4bwK^qpC$~L^newYM=9hfVPxbsvwVI}4B-n`*O#NJJ^UxZ zRiR&etB#1C1dHinWbQNke;tcUHzh|f6@ZW9b=v%0x^Ejk#SZAo&}6wsUa8Ia#m6Co zj(MNk$H0LBMO;H#I)BWZnStT(^iECBJmgi8x`k69F78W1%Y6Jlw0ty{PG7UXG>~W0 zg9e3bdS}Wz=^DIQk^uDwKMRqa68VWR?s5Y6m`*WzO^|g9f{h8RO~yb31+YhFOM8k% z1jPHnAPshoa-rnsmi&-G&&>S7;ps`jyS3nu5J0p5G<*`M{e4WIu?xlR(Ez^>+%3-` zO5^u?0%Wl+6Ev>S>0d`=om1NISRQWDpbkI8W@F>8z_KeL?Eld97eG~o-4`%^C;{n^ z4hbm{kZzEc?rsF7OS{--GY_{{O%EX1n z&)#dVz1C+zk4F$Fr4RTA>*(FPkI6$LGRec>~EILzGgf;r>@mSGb)pIM`5)U<;Y?_Sb6yN&eYPx^DNy9qaO~e zUd;ww$~-))SjX?EumWh@#k6lh`ho>J-@ve)7UA}8j)wNW76$|b4Bniwg3Ue>O813V zsgb}A?FYx;jRs2+tM2>jY{@z_WH&OScPJs$FqFunqwpH*af6Uy@cD+X81ewSnnIA* zkQP@%GZ6?xfL%B)#ig6ek3W8_1l6(Lx(u?GXaQ^kW+Eo=lNU3T$kK*dA~u>-$no zR+?=`k?Yk=JK+SMCn|y2ZkglTGDM8Fod{%n(Y7w086RQ>Unck*g zq{5PZc<5NFEzfv6oOwt6<`XZtIKZtNpj&m|fRHtR+80iig-hPxK((Ku1WuuH!eFqy zf=(%%U7bt&MpWiq;o^Y6{=;u%vW+F;ZC#}!4R&cbh2bD@5P%hiom%AAiX>fZI}Of7 zt;DQK4CcC>X#NGcakX`Cw+MO>5JchJAu$1Kn&?H3a@!kN;IEN4>|8F@HF4x%{_Y`H z$K>|DsHQqZ7Y(v1!-Pr`Eu7C0*s;Y7yPaJV&0B=fRulx+_b?Qjb+HX!6za{i89zkC zh#oiq57$NRDWPgo!9{tLTp~X9OV7deKUsmGI`>}laC?*~=pkFCNk~Az@0P*uvKB;W zNXBiW?R)o3`mLJUa3AaaaAhysM+s`2Fzr~GA8a<$@fT8Nom`nf5zl~i^@%z3=KAa& z$mhVd<0;)_Di#2Z35zOX2>44#eI(i>0^8!HfB$CJ@&tA(eMW~uu=bBHPG%(wW1fb( z&Yhic&Psx981{H5E4{i!NCBKVJ@>rGO4`gXG**#XoV1hP$bBOp&|CEZ z&bQ9T`x`^cU{`VfjdaF(5NRZ66QXPFr+1oDGBZgjGrypbDC_D&klRdUn(EaZvi<0& zIz4@KhJf4m50`SSQzv1^ET9u3i7any{Faq9w><2ImKTrw6pDvO0)z%DY^J)u>(y^}P+Uu~X4PtS|A)J7k@qC?Iq$EGUFWB2cIV2i0V~VvH%j zCf+>)k^5rY>HEWIyHLx$`k!mdy?Naq)M124!P-^zeoAwCheo*?#fycl(og7}Ke32^9_vearX&q~vG&o!p2J$f&8RI{}!^VDRW5br50)45k z@3E^33X(3r?DqkcYvA&dj^_KV6^)umsYoDQATK4Af*r7!ih?9NqkDyv0T1^S9|bN8 z`?a)fTNRrOhaM@fJPU>~F>zp(oAVFyO_4G8}Zm@gM2^J2*(yFORLQeC? z02R2u;5B_xtQF4mE%n7*#)FGiYiEs<^yz8Y%n%=lg@OP*SwY`Uf%D4*~8iq_8wxnDP z6i%n@@8xK5tvP{XqHY#bK@|WwI;)N)9r(CA()0X6wPfar$OziMjo@4_R+DANw7%rs z8A5wTBnb-ljVV54CF~A$&3Mn3?j6ZF{-LTxBOBsxoEjSPkPsfMdBCTOyh0Ih*qdJZ z!fR4!V%PTllQIPb{4VN|G=Jlq~WP9|jZ;ChC=p9qPdWH1L^5 zIjY;Ey5uGjFdSmiEix4};f|M-3A)eK81mS`Xc1Ho50`KY>pf$e%MT^a)f?l+>h8+d zxgV7!J|aU>*#w?M$%dmW(sL(K2vL6Cl4QZNDZ0_3t#Eg-O)2J zpg{6;!v~AM<}y?UO;8@Br0*i&j8V)PvtaPg9@3n@^e4U{uO_0Z7N7ET<|B|X zZ_}-@>N*}2S(kaWxX<>`nJM2(GUVZt-SbT$>R;c&uQDQ0Fl>5mV&xYhxDS*m-EzA4 zQwAx|P~=|v)EmA#j)xbmm#F5HsZsyxS(9s_$3+)&0xuRCllU{wsBBD+nXYPbrmO{9 z>@Hj3Kq6uAkrMC!I+GD4Y$^7GL^tvha}kjaz1syISMW=P7<%ny0u?C%s2ZpbtQpG4 zk}U2L8$3t2dX=XUM+^z3;_F_XyE2D$Y5$}bK&g_PcJfH?|8;@hvT|HY9+<3nB>n zwefERVsf9*wHfl&ru+BlgUczfh-4imooumud=Jhto1AnxTbsM0#?}d|^ObH%6c042 zcD7P&=C_|SW^j{v9R;D4l@-wW+$0y=WBp6_R3c;D85H|w1v$n<8SqF?MbnZxG}kHk zwkh*oqnjQsFM7%f^uZsw*WbAZ7L5cy5fYSON?_5ihp9H2_i05906-ID;_7MJg24>+ z=NbU&1f!YLy{3CRD|Yzy!dOOUyA)}ZMUU3EekxC4&2o8TB{lpVp(r#*-3zG5CTmgu zJLdo8(YHOF^u0u7GT9mT!d83x=f$1{`xJ=Y2Ox$ecK$oDs*|j z))G!9JZsK2sAo5r$nwV7N z%|+3$G~B{ZzPgFsT7b?t4W#J-1-NE@ADHs_Lvg=Jm>|F(;v$57#Dz{n4P!$O9BsW4 zq{>fJ?L8Lq79<440m8rH!1wzJTq&*b!VC|2$rBMFnM=$}Zj(GK5GPp*+CLq-^RvIM zO{U6{BQSKMso;-H{csk9*glD7g;a4FuB&Y}IJ{ggyFh)5B@v9jN?^kB7xUH%oFaZZS;fggwwR_j?F?3R#2Wp$A@$d)n*kVP>l-W7|s@9AG zLAWmq1AkdRs`c{n%phT4fkPTUrY4`iWUoQX=H--sapU%+O;|_4p7ESTF5_ zfrgNzqeC(M5ya~!Y_>i?`GTOzjV=;Jw z#1Pgg^=glR3fVG+Q%fT&wLN72zvNh-`;_4PtuB@pl3C&X8`y#R)fh&VdaG)^t6j_* zg7*}1*4+;a4!JzI*{QtfE~N{tAh(B8(j|%zp0U1s$~VAuJ<|v!u9qQ(I}_oDcqo^I3A&VIBrIwS#F{hj zYzmoJcg+s*FdqOI@pR=JiL%k62mBZ%3v3D{n(Hj_v?XWHN%((bmJ4md+FBg_o4Gjp z0Sxj9p9(ehgjk>?5$snqoNgTb-Z&Ta0 zwOZ*NqQv}DPW;8Vpy0e2H*p5sC#|?*v8C$nUXM|zqL(i3h+5X+|D}Xeqj*)ZA^|!3 z!I2m71sx)5PC5U*?S^;V0yUP`x4r@JE$klUfpJUz=cC(^)r;)@CKC$_aOle^E2Vwp zEvAbddBEf9PgV;C1{YBH^Sc^81}m&Pf}(kU1@A75D7+6G_xo|E-j}Ic`ADdz=@R}9 zeWRILR{wNR+h}|DwSm#ktEr_A%|CxiNzo2(h*M`TvBkhs4H|3zKAxIy@Wc3T`}-G* zHE@B{h=3%1xzE>=h~FnuLSTzR(<85k?rm|crUe}I+|I{$YE0d-NIr)Q3xa#e13}o? zM4XZnR%QK-QE#1Wk5+ z292Gr5l$~}O_6mQR^w`7(CgPZ`uqU6(8>DFwiCW;-9bYgbP$>{RXiwitt>N&O=4BQ zU4Cug3W_UdSJ&WzwYeyhPTZUvWS}fYAy_{?#Ay2UYQ#A$echv^=IiPg@xn}pvKf`x z@&8t%D<f7o^-~CiFC2a0r}ce#nr%SsqPH zw$*%9uw<&0QZupO_C1_`OID2PfU2u1fv{pJs+NSJSsqiCY-m~Q=c@zy+95?B+VJe5 zsKFeXk+zF9(h-W_|I}B~WJMaK@>H=TCZhw#Pfbi@D&EOdcv{IHC(+vmxy)tcTr)U& z3Us8`DlIc2$0L~{^r})%unOFL=4iIZM@8I5+#P_BJ&1+4GiFi>H67&wf3Q* zK#x0FmCp%ob6~sPl9Pm0zXuqHj&6S#FKuw^46cLx0c;CklO%jXzMtb`o(&(?4uG2G zM4Mlsspo#sP58$rpB`+L-YM=Vu_&{=s>hb%cTJCJpQsQD&nJz9CQFT~)!%p)Y$QO|LjI z@c8=^EG3QlH6-NmHEmCWAmiT`(ahdt&<6c&KtIgS@96|hUX?F3JM<` z8Qxy*F5$cF_*tE+wB}~;B7;!S)n~o-#ld)M>ZGV5%tTvU8#ZbM04J@WjBd*NDn-H{ z-%O*bUZTVKqw(pq?OgpTdHW~o@|du0T8Z(=5-8uGr*Xd^|Mi1dG}w**|AptakIe-d z-*DBT;5?x1`O329PEb3;W0)s-CtLMk(0w)qP*?7oCqA@#1>dZzTvzY>{p7XjsHif= z&Kt<&2W0$}mGcQ1I&Pyo1!VJ6EY>RMj|tZrf~eV?($!Cqie5NeADeAaJ-OQk*01-k zPi81`zQUAm)D8A`fd!JFEOVlV*Wl|$~?vO3z)-#u6{HerCv~3-Mc0@u-N*pVngB2DUu2yt9mw_+l z6Mlcw;$P0{R*u-L8v{KY=k71x=L+wlL4`thYY8m*rx{7w!&lNRF+uPQWqe1h>prB4 zeli}J<+D0A%OWg1o?Zk8h9>5fqi%iaPhpkeLrFqDE&(FMP7ju+u&e5}AQ2p^B>j4a#suR(&pKnNKn)1N*+dE#?^lP87 zW<4-R`2<@0be6*EYV8dhJG;3`vl27(&I$yKM^RPdqv{AyA1;J~`M4D*+;WkWjau=& zcfUV03u$)4T}V?G$0i2~^SpDFDXx3(C04#Xc|Mj~P*9}41++>t)~mj81eH14wJNa0 zp}{?aDvTFZA%^DnhrcJ|=6IjLur>D_k}6xrw2eysZm3(8Nl|8xZINtQy`=e1V|B!( z;gw-mXC!jU`thQ;6un;(nR#`cg!M)X-`HV~9;N|{CY-9hk}C^D^L3#Ze!tk(B6K+C zmffYPsm~+#OisNgo;teKY~SV$I0n0mxYj=~Dx@t-mHFjH`59_-~s% z>bkoyCP9v$e)<2SKA@Gr*dT0jq5ALIMp{}q!$|!pdi z3G&gS;(YmJU@buev8C#@UarZ-6}_HF5j4$R-UobAZcaGpjVd1~Y*#$WzT>g;nLLBB zB|OO^5*&Ia?Su&?fkPqHuBK1_dwBtXqc^oX9_fc)j+q6?M%1y`3b3=kqkw7%6-j(fT)U|G}_pSY=oa*Lo*V%507Z#dhih4wUG@CE1fe z*z8-C-aNH05G@wIw#iA#9}~am$D)G8G|A+q6rdvrB0cg)-l!)pIy-yQ6ynHaH>5JH z#0G0*nFiK$pX{<$dcWB!P5aKfJ!9{Ijf2_X{lAB)f=~H8-kX|!`!#ZMdp`eI z$ii99$HxE|FP+cZ!}$ZL`u+@`;fiP|LyXy6ry@sM-TjACJXFWHr-fcHDYKtE zqD3;qcG?#W+FXA;&}kA$34Bz%4k%rUGCeI*04ihz;5HtqOM?H#64MhLu%szUD93af zoyi)nx|sL~=}VHm{rizKpZN3H9VDUlKxb3PEwQzHuvr)w=B)o!?auueffD^5Gb=QL zl-q3&K4V?@{zg25u$5F4{Hk92Eqg?9iLO>>JE=R8>>%fllhx2yIc8SdvkqP?#V zZVYs8OmpX%5;ng&A(dCik1L2mDFHHC(9>AZ$vnac*QtI-Ja`Q3D`x&Ej}JN8a5pLI zfv(nVcEX>}VtmD7)%oSD^AK}h) zlYl_o5H3P8Rv1JE(M?>ba-)Psf3mu{#oavOoz_DS@WMK|B%KOi-Uy= za7qGH3tHg4&X{cj?8=c!m$i?i-BGDMY^5=izQ=2KTh*XyY`{XIyrg)BsP8h3!)sz z7P+ve2ISU#MMPQOI>JE<0nXtG8-??3wDi#`4EV&!ML^UYV)MR0ff!g=@M}rX7lAbU zBVYm{4AgmC=NvcwfJFm4p$fnAQ3?E`V9hq(k)H1z%bbph3*q6};Ts<-i?-Mu>~w!a+u61K9TYtfy+Sxr9~m|7&iETg#$Xn_}`AfV7~Eji%r*+z|BHl2B3cRa6{n_CT{wbGDXvgAV~Y zJOuyh>S046QkXYVXGK&o&p3PjAgBba$_CB@=^=mQ4vuWtCatAnf^!?y9Pg&$E$cSw zTXXHqkLLKoCI5p%Vr6XVmLKK?pzrkcuOo?EZ$*R#)D=9ueqn6`sF5Qn^O652TkC4Z zbFE#U3=X4HH(0~XNnT_X*Dts6JfFRmFtBTMr1GCAreU;1hi@d^kaKme9@&+t2+^*a_k-<~r9enB|tij+i! zR#xnu*VW}>49KD=tElEs z?t$h81dC~D%fG}^2wqsbo_VmQBZ~>Y>Aa@gK55h_NvzYG>su`2nIE#M@w>jh2bOtw zo`znhk%b!@pwu(+?*5dWoh@>=`C3U~5^YL-ukfV5mmD*mzBFDUy0&%}pQmAQ9IILr zZP~g;FzvLYkpk?yCH^W`&n+%0;`6D;q>y94PF;~{ZTia!HNbYZ_SOL^8td~RuDmcAoX611iut`Qs$58mWe=Ymo8GKMn{ z^hJP2u;td1>49o=oi|lm*_atUawV8BP>I<*j^0EC=160~L4D!CWY3Nuq6;TB*3ajv z0k|U!c)bO(!)2QE39F)g$H!zH6RLj4=SUxK){cSCPu)+riC!5D!5eG*Qkyk#z^=lZ=GS&y%mNzN`k+F8H zo6x9e=`0RHaee{H0}Ej%a1eWh$$9hkSgL7u?^}{=9vMI9E9OKB{*i%~Dqpw92zRzd z-I5X#_NGpqrxmiY5Q2Zw$7{t4MCB+W{!SOT-{~I}vjxAQLdsGraQY@&UK?f>xJAA>72KB6lCnj0|@pcG( z*{e?Va%=*{EzvjNC?5AIKA0gPWvGfVKFjUPdzeROd>Z>pSO&ZoY_AcboWuw)sAhkx zek9RKRJ?5k{*u2LIHIf8ex4$$ z#dUWUiit}%=j5&@t0<~GEE2i710?){_mB|ArUaX?6kPtrBAeiLoR9>t)HBH zkMPhIWG%632%r&Na_FRm;c;re>&Bl~&}V)Z5~%s+NF?Y>c)+7hz@G&9sq$jq&#!C7 zwAFc46#`L?qKpW&cLYViXqa_5=N&mqM$bkvGrVtWcogXH5*J?Csg`gJsSM>?sM*;? z_0g3nQu6RBQfcWk^{_J3k8u0Veadqyj^9$mG}M2;2{=xS)d{j1@70-sbMO|l@RQV@ z&ua}Ia%gS=h8JfTJVo(a{{9bI<|a3xKXMU}&n;^j>+7jlLNtmrU@;(aO4ON>6r^%+ zmYK>a6V0V)=@3M%rgW0FUu7wyM@6DxV!mK}(L2~?Tv<;ip2BY{Wh$mhk6brx3w9a8 z&A2RoFl4=AB{_BRBP0U&Cub=>Mea?Tj1-newzgcX&^Gs2-}oqM&}Bt zExGWTWu9kyW8`Xqkp{+shKlO55D+qTRua#YJ2(PpK+#yMn=aH;}apM+xfvsf}Fqt@-I@$kIrO^HJ=1OWC%Jg zwFk7!35%>C18Iaj)nXtevw|z;*onb|HaZMFHQ)J>pZ{}E__`u5Z_?bYY1Z{i%L()# zOpP&6@<{w5E!EDkG#G~NP--__>*272T{5bwW}v41*+^CYvxjh}RSmr88;O-_%c^Oi zR;e88re8L8-?78D*TH;&j*eDCQ!`CLXnBT`Qp9_%IY^AN6A&*22Yqf&e*#0RTIq>8 zd!E6%W1jBZ*J^21N7!O%UkNI;m$U)={npf!JZ|FvXSpbg>Qq{{{K0a-3g3X@pUC>eW+emtx+PaIjEbq;71$LsUok8gf{6?U9_ zQ>hCh>!3)pIX{U1*8UP7Ws%o^VA?l8xfcN&&{ci2Y~2x`#b3x_Msn8+pJ$K^sy!8i zkQM@5=cG_hfhg%H*ly|AjqK|Q#i4P}80@Jpw$pNUwr&UqY`IG2)b#Xcalh>97xOoV z--dN*&Gl(obH=Ndbp4%}nE11hlG8!ipt)Cg7Trs(_#IE7V+)pdW}S}CY~&Pui%*8lUOkM*_UmFrVU2ZsuW5+Vr9eb(p4JW1J~vSCBn$db-vZbvJq zi{lqKG@qb_LBC5gbMv5zKGLskez&8$(j$c~M> z9&twgGn)r+D31TT+>J$=`f<5iL6vc|M05W3dvKjWlyRjtaM&K(`~LQK{g&%y5Sk9) z0;jN>{{%P7+Nv1tspXHJii%K!ru)8cxPUX@Fb`Zp^f5oVvT)J!NcTK{8v9w=H@Hw>(A&uhK7DLtX$&RZ@u=M z{+v2o5bdll;Ac(y>{-buNjFp8Nlx_GV2X;{!MmX0o99Rlsc<0fAu(-|^26 zA3gv}a%OREAV=Obo0#Hhb@!o*J(-#7RNd0@wWZ}RaE=xzrh6PL2+ONDr0e$)mg<(F zk`fu}s_GjV5mE?;s(LP6#Qy#E>C>mBAT)vybRvfZ<3Y5qD3_XE&Hr|uVzi7O#^tAU z!6y5S+roLOz?d9-(3E)z!2STDP8583cU|VfRsQRMgJaO#-26z8$90DmOR<5JDB}o* zVuFkwG%!7v!3+-_%mbpSU(vu220jr49}iCjRabEzF$JnO^J;Ub=lvp1J`1z1qSRbeuF$B3zC8{MjT;_-7NJ zYgi#y;7(~v!)<)_P>y{Sq1M7PZf#cjl`B>64SR!X-q?S65_yA&swlL$jGb&9coSmL z>P!i}ZxF-hL|pqPZ@yLN==Vht;CZFkGp0!2tO-yOXrB_(BK-Ytc$ z>`u4B`QyCK0Y+Hn<{Ixd+M~|0G1J>9&Gy%F6O`ZeHFu3!L~MsIujvxp?jFiKpDPzJ^qo_CjTTYSWN3V>_^d)7pNoaxQM!7J6G z(!4yK&`fMqh1?9GICj^YiFnlc1e?vtkcd#C_?XXc>ZVQ2mh3XTQswF5e!Z!w;o=!= zd9g2s386<)mj8X1=Emo`64MvBOzC}~IDG>rM=-zH)AgY|4lJwa(8Xz~$EPa@t<>gSIE%$cyW>wX| zTa?#~7QY*ZJd)B%kHPv3&{5Cn{)hyrIjc=~>Xs2eF|W;Sd9t>@-?B~+SJ{nh2f}?R zDoQ6Du&AoA330;)Qqd`&*yk#*#`J)9n`)76tBtw##Z$4+UvK!m-HpKNR8-W1Q8m>{ z>VLYv{=a!8k4QSgAER;G1O2Etbtb*KJ*qH?M*I14JbFw4`)}IJu1zllsXv)$Q^BZ# zcs~>#&f?*EWw6W`G}b{-R_C4`pMLc zR8qKVI$}4^bODhzK{OGftzc=I!dyKc{rY7nvSTQG3-lu-n}F*M+Ikt8@Rw9f%6DHMpi`CbLsaZ}!1sC#&9rf^wH zN0O0~kUWNB10P9ZlF*XL(*Eo&Re7tb`qP?|-^@(hv(efr1r9+B?&l4&Y}U=6iQfV=ZBM55S#7RN$^jptheXo znKsVVum~ z%5z;az-I%rm?vk+4?q%%2mAxyMR}iyi~SkDCmZxxH-&&%pXog}PqOdiDGl^H(=S9U z3lO)dK$lQUK(Lm{=K~LcExDy-JTS9A{P?l@^Jm^N&9|H+3i+-b_bn0113>P?*I6lb zUoZMvO%@ee^*1bk1n_*;gLrr>(eGt>A{$;FTvwk1a1Uu7rKiK|GnP7;Gk)}-)%R;2 zQn%=$-7TcI7-%*bEgoe_r;gpg^1Fy|9yE&KI4UPc(s1$PO;IG^uUdP?0l3(rgPS-QZK;-V-+3W3(#2lb> z_uLwJ4Y^;JoukNA^OHl(2RCxu0|dEPxDj0)dxC?RypGwRj<=`+`X=S)1E`n$VG`^v zTj-E7Uk+GD*!N=%bd1fT5lq{mk`yK6O#i_Bf@xOaaQ1_5dMd z%<45-_lw2()c$@--+DvsCyzbIcn`K4oZn{WAP<5uXI=(l(x#z1Sz z2!%>4nTUV2!B9thOocyP=U3%k$xBCPcXROzQr6SE?INV~Sf*_hEj);7yOx_DzshfL z{v$1IJ1_liTY=Px@0AQ-@`{q5S28Nsds8+A0#xgVQ7g+;5t8Q3kuEm4K2L_bb;a*d&2TVGgbYTg*h}9Yve0k4?_DT9&UYLo@Zi z^&%TXi`?(Fzv+1s31b8j0p`qCGy(^j|>LUlwqoiJj)<$BXWY@77n>D%#&zSn!4@E6W;r?e2@|F(nA! z9PBG)@P4zu{~A>`e#a;_;CX=LwJ4^jGijKvxGwnRTk%cApa{Vf4X*S+!)D@FZXZp} zEjwY2Z(4efl z%la!jyxpX9-}=nK+uvpj@?Sd+7&oBgX|Wc`wLL&T-}Jf)w_heiuGU0bGhCr zU@vL&7YK+_@JJO^9NIeXqI?}l$apDB9Pi;(-Xj9g8}Q=OBo3baW}ez_m)vd0dH(Vd;*lfq!)VV(0=o+p|ZoDhYYT% z+3T2gP~xRwzUu$y&*{EhOz)fIy zB2+GUVpMLEa@4W#qH1b6a`#vwHp}&{)LY}_ElOo$yyrjz_%Gk<=;fu$li_nzD%Yl( z{+D0CH!Lg^&2d!lT?mb1OYIjNv^;%9#OHW>vVe955TFOaFT|vmQAtJLit!<_4@ z!oT+AJ}hLwym23n;Fzyp;>X6WPNw@|s$!`AdUEzkV+PDf6uQU6@Bf~miKSqR!2$j$ zEz9j(Mv>mlO4S?&ep-hxneBR>TAQB^QEqY`CJ_Zg9Nu3sON%%Ur9ewBmlo2dE9^k^ z-*rE$*c9c)GXijn>fVN5MS$~TY&#Gb!@FJ_yh`owWh*rszC2ET{rZ<~dO1L5Z!z{; z4m#$6p9G-+h0YnHEt8x2mE2L-*>ks*zHe^eD0P42PY<K4B3Ph>D&?c^B^p5dx2>$t zcP3r#Z`**H#_62UtCds~DyN1Isws(MDM_KKV1HN0M%&az-bO{`m5(?%^sYv0HU#{_ z(1Nb4(Ae0R&Gc9b^-?Wxl-Dg2aJ$o@#RYD2A?PSb{=f`U(e-{M4g(BTD=Qtv*g~p~ zj=nWEP63fa(A=K8dlu3lh=KOGNKKkth+c_2m6Cvh?_Eqzhn%SYUvt)Ec}2!2vYjWt z$I4P+`iyY}@@S}-v$eKW64aHtWr9j@U-E0KO7if)8gI-3oKVISC$)Xw@0uDKaQ;-x zOQp`-T(HJ4)h)8m5BeA`9n#cx|3=R-O(=Q0b7#B8o5(16<(3e?_7zgEnt#bRe>TL6 zK3l(DOu&OqGwL5BA89j$&VM}51*;3_Dk%H?FUbyY;b}C!#WHmXwj5Od#`0=@PFQ%Zr(SYj_Kjz z;Q_QK!)?x^Z(7YxI&~q8$qzLH@}Iu{=|(2#c*$re3&#r?>tOf66KTGw{amIgXU$U5 zH_u^{n7G7T*qekTof;&8|7=|yRPn0%eFk?=WDZY;{d`vwwBU>-OpkKI;xgU04z-Lf z>-ti!!Fjq_kO|UT0S7y~zUzIz{n$rR9^vQDx4-(`4u5*qw>HqCvEg?Yv_4jDkeVjQ zv@bSSJ}V#u@JSJ6S&s}eB2DVp+G57FJ#g=3SmJUsJNu0QLyLcGD2H(gOm&W4lk~{;+ASAG149aj>adG6tBs06Z?ZUcNW4N%w{( z{KIi1^mat+cF!#un1IyoCduT1Dmq_o{d*vC>+MZjpm_1P+Ve z1Yr^#=?1YfCmj*2j4O|!i59OU>46-tn>wfN{}eh&1A&y5#bBiT48|Lzi;MFd_gC(H zX3H_=$DGEqdp@^bf>TqSL|c8wI&(Ffb~;gcR;pnCS8w;$|HlPDeHMQ}10#^}hdkgY zSXl+d9wW+-J;e?WFt+knwjB;cGd2q-VJ3CsDzQs;8r+W-XwrTC+{3n{%v;!z#cgmV zS%{{8p#02t{~SfZ&43sqNPqlECA%oZpsdh~1~qub`n5+3mE3f$^J{FgXZuVDyvaP2 z^;%hh6IBGVh!xpcGV^f*`d+((QqjWoAUPhhCZ@mt%ZPP%$r^ewrgxtqbPc=sj7)KH z41^6G#tqt9ZqJN-Ze56>kK_U@ZC@ZLig!t7x|Y1#cWd)4#|PrDue~3QgX5hJuOmE9 zZ$7umX=tpr2LxIS2wt_E&uOZC+QKm1ovMKWS@KxGQnvOJOjs<^2_#^o=UL**} zP<7sV%;{7`z51~`T?dh&Lfd0yLPtG1mzPMF9!TZeyiswzuQb21cr8b2Eo0d?A8K94 z;Z{jAF>w-Dhj0b3{+q#btGl!U2rL!FK@aW&JhgK}pKjkS3P=nJv38nuadu%}mLvT7^f0bLBhI?zbv(UMP5-#WhR{z&Y#Q%OJL zcfYUNY{mdQs2E>=gDpWJGEe$egYAPnL>d*07COo@kEgqF94`(QZ9llUxUjZVe|ZW-*js0t zJuZ*T_nWU>O-#Pq`yTs&o6~*PCM0NodxhcWvGH}1j}KBd&}gyf-^$=mh?g-sl=$0A zZcSib=F57BQ7!q>;zAynU^ltu@~t$w-t>owqRPJh#7^}I$Z{w;(u98s%Q6YUx4VPC zDha0^iu#Z{JifzF-mrGH9CdA1*l>A8T3%9CmdxfW_G^J^R6_$xM37ZQOhrZIZmWbf z!{O!^xcX{1-9SpA*0$~NXNiZ$WjEQe0pwtCo=0e;eb8}?C44fT4JQdzSdB7`&qi!M zTk|&^%60>b%F=2D6x=2qD?p7dJ39cXaOulWA+a~V&knL5Om^PG;joA#=Mct?BETYn zg_3fYmX%D;t|_PFKOvy=aJGyt-!}XC(T&Ut*e)_1brJSO2|A4pNmB|GzH#vJnWl03 zaj-}O23#Rt&W*o)55XJq6$Glk7`LB}-#e{Gk#CuXN^}_cHt1u3dJpSoWGb7(!k3b- ztyzu5R>qE%CZDsEj|q*KZT+fmI^b65E`@c+Be`Q~q6JAHP2bDQm)!%8{EH2m#In{b zhcR6YLPD*q&X#=bQr3E6bAZgm@0VuXZCAZ$<=gU^jw>OQ%yWZNobpUNgJ|3W0_z8z zQJ-CVOoGe5YFFC)&HdY1FbKSVw#q8{jTP|30hl1-yYx2G=kJ|zfT(fz+3t1Xqv6aL zRk}pFH$aa1bFR#!R_pd#R3u<>6vrf!+suId8Wm05$krB5iBSDYmUhTPgj`wVUZ`#} zKsWO#3S@Sxxa>orq=%2ERNb65)jb@bc3dU>NWo3%G73GVVD0UFlk0x7p%)UNnG{t~ zHF{Oj%;mfrFrmujbzdI^Og%Q!(4}jpK?InAZHQyl zoK|i~PHF5F$|v=bzwW{teR5Y5ajUU9qB|E1J$*mR=F?~)Q5H%b$@B^xdMyf|l~0+uN4X&s{Ny-&y{+(&i#S?{ zxb?U%$NLR73H`>EDs@a%!&c$v9Mk*9T{Hr<_9ZhlXpnrT{N_q>3oRL@(A@>idfIX4 zhYuaEo;{OL*U)G%{_gEEs8S+vYyn!K5dl*`(>aTJx& zY!^vSTN}vcKDu~h=-9>8*QPx+ zF~N3yp+@0z!U{ZXIr0aqZA)14BQ!E?fa2{;p$anLlP4t!kjAJ+`S#k%3MM(fyn(tI zCPjgzr^cwEKoZ+67PXcv_J%$%4kkm`NjBO+*a`va-B$^$Vi}|-nt&n4RA>| z3swexAhgWkhC;3N)d$k+ECb%!#%#cS`s^)zD2xtQr2e{yQ4m9t`43aZqu;%#{Om)s z5<_#Rh!(4e!{TC#N9VlqJl|Zl6D5Qs!kenYn(wAc!mxltWoAmgEqz9zEaAW8=y)hG zT}OW`_!O9vamG0(NABx!Na zt`U4>WmJre+-@<(e^O4>J|TQP<2^j6vA%h!RIFHky1yEy)cmX#1LIW7z{h-vuDdeR z$Ih2$ec%L{+qU>K&%W<4Cnzc1_7#_g)l@1E1CZ~qQ4nu^{r>JNiSA*>i%k6&Xzjg@@`>=asZsE;0RZ( z`(}I=zP9$$?`GLV;`bnHX-SFWY;E5W2?+^sn=_d96-~nu(f>Rmve!dn z@e?fst{r5nc!OTzc>(Jmp(?74P=)v8+d#QT;Qf9FuVgjCVc5QY?X_h!)>^E3wYlZx z7C%CV3euc@&fg0I`LeJ{9XijVXCGcLGmAYC3p7eVj$Hk#@mx#a>DRr$ z`3xEmjhXCYY5L3Q)0gDMWhxa#h5@8+@Egjj%&u!OR;|a&4b+T`cq-m4TpY%M8k@~m zp885K`Nd;rNNlCCJfe^)oRfXwA^SCwQd4hHzMlS!n&C2Nf7iP+a1jev5G!#B(@%%tkH|P^l{-!onlm4L zM8BZ@fy7+4^1^m1HbB&#wtl=`=Jm+a*Vn)smd59~TQwoT&!)O2tqC3#z(9uSQtfhmW-C0b-^$z&@T0zRIiVnS z=@MxWlT7=~w3G6$nEd>FC6Qa1E0UDa;!g03KiOUnQh;aI9g)ec#-mm0a>m&~D zb12NODLl#aPSOAU{XMD#KI`cx{BB3kR0vGzYUt>QRQpbTd-hrb&BMb3$>YTnlf)O- zHrr$NU@y?OmvO$TbYnf!D{daZzr0pDVJQ^TwH^IsEGmrT)3wx#q2@Z#B6kj^1FWqV zGbfwUu+IO7s;>^Js_pvT9J-`MO5o5Uf|8PllJ1n01}W)IX_Q7vx8k$Qgq=5XXF z#%c!L%+bGyusr3*mldf<0k?VCk9>#I#+hDeu zp=!E;x48b5&zBtr$-zX4wj_)ll3ZeXXuxjMgJ3U+y2bQb>7V(-D5v}jyk7iHHH!a zrmL&#aTnmOmwTXBZv37BwY#scueaBdlEEGvh?QJ(&mOWjE$Hj;N1YL1wVq<48Co(E z%sg4PK8aLh5!)cc8IM4LgAS#b`POp&LL&h&r0OimNp3<;#XQJb zoSb=kN|O$4@t2plnc6m*FjZKMZA>-6PrZW3$oIPn={r{MLxIKV2unU-5yv>u?}HDK zGRNo`*XY;_YVn1_oj;FPg#Ua9^2z83Rr0@eoDrCqq>US`^_22X<^K55-YRFo1P;J$ z5@Z-n`;(K>^)o!T^}MeF+vL>L#x!*7)?AuA$N{QlaG*creZjY1vjg^{5MR{iHBB|H zABOXJ*5XFS2(ZaDL21RFoBbQ3l-DkEXJq4QY<+&8m7?%?Y$~|Q0>ao40B6qb^1Y>Y zvfbqMd3kHwD5;m%d^RHp$DXok%$d0hg7X*AV%Damd>=<3=txx5V_eu#^J?+GKGbG= z^DcHx#(m&J7r*h=TI^tM+buImL`-ebif$;C6-T1z3KY~p2oeK0Id2e?NH>Tk|5%L+=SZWOTTcw0Ltd=?K9- zp#g3IX$D!DLT<;aQ@@)qfrm5wrjj2&Pyo4+=dOziz~JEEry7;i!x1t8G&&6@N7echYuq>%H9^ zk^ozFo`?poo2n9CrXYjsHzX2Y+5RR$$(itwgj2>ZJ}bwKURsFT<|pBo$OPmB5SArQ zC_Gg_WYo=@S3yKq))Y+V3g677g+XFoubjx=Y{6twL)sQ#5_f`;Eb${qbT#shlLxuv z7f&SeB+{@(!YkO*3uM7O8S%o!^VWqDP4+NIagDo~?JjSNhHyzSb_HH0fd8_H_fw+c z4Bm=ubqoxZN%%v{2CeOa?bDkkcIfbY2vol9B)$2A`jd&X|8TO@E@k)eE^yHgbz zX%xg}(B9|ldHO7ZvM(N!MdwHH}Zay^}ZJW8`t48@m+WZu1eL|Vo_uj?&Gl){pdg>7V;d;Rc(awikr3~7 zw;?2i1}3v$N^c|}2#ck=zaPO@+xCtQ3WBCw*LvbVf|}qDhyduxk=x^()3uhMj{*#t zbC7=B&bt~E^?54tg;MBTLI{ovfYWzS_c*jffD?={`upr4nF*q*pIYUyr$bJ664(cO zvMTfiX=hZDo|(ziizr zfkv|^4Q&UuoWurJ7K_mnu84Y8V z6RGZY8Rx6<(AN*Pk3U)?r9V5ksS%rpTS{wwo>LN{h>GLc31vDZ$$R)eS=OeYcyI5E zGF{qQ2tX9G+&?QF2W!sU`vA%fU>;vFY$V!5 zz{gdb(n1HIXMOk|xkQ}A-z|lh0*T)8cQN^~&y?Ci16rd$O;Vy=LWF_MQfEQ{w>q0@ z3jk)6{#*IM7GNaS(Uuw~H_Lor3LM}}nGkn+Q4|$hKKH(ijugD+X`j1Dq81HGa~l7C ze$*YyKqvTJ@a~s9%IL(zfs%;bN`JMnF%l^Fj09ZFxjYQ`c(+d48I9)M96UI@e?R5@ z9jTSgLR{YWdzH!0*r=4}GU!s$-22LMi&+z>zUN03zO=Z&P})p|uVf687!nk}NcGEv zEr9|iIh8PrJ-IOL>&*0*^PSP?y-^5gvjN`6uIU|g==d-yTm)*#urq2Yeu_`jOJfm_ z2dh6)VlQC==TV?7omE=WKWS`&w|HE@4*C@#zJmcmiO9-gS$H#H{`tSC(2vx|t`x@_ zV7L`F0%eI`;!j{s7l?GdVLlO5XP&R$W`EgvP-o?ec)qmuc15IYbxWXLsd)H#vVp0c zF3$h2Q((Z_WO&dKO1-@Sl_NnEWt${8^t7&?v+tyEd8G@l*G`9*l@-=|8ZjWg`$~!q z@Hy{d1&UC7WnyJrSRweSTlZ>yfwGf`U7#w@vXBAq>C}`*+2^ z1o%0bBtcuma07AZHwt9H5ACNXtyYgMqaP!LiVBiBaq*o2zq9%{H)KY!4F|C&S`rOd z6Ic3;Uc`-z85|sk*M6>6tF68->`R6oOl>M*P#)#~KkxRlJee&Eba7MDb&~{LEC5s< z^*a0$+|$bqP6RHUCUg_h(_MzdiJhwhvfv<<(XwR6__0_$0YHUT8G%^Kl3FdNj;~}l z2R=wVDBWc%^s_GJOsloMN>VY?b) z?m?L*RZsD9sv+7%Z^dXcCOr-7T(x|~${ZlHw(_E9Go3erjKcW15GmZpG8Fa7E!T#T zJ~1NzAH#Zi%a;}k@fQGxJ7m?6Emk_#f4g*-n8tWMQ=I||XL+xbMTW>Vb!*ulhHG;* z0rZ}xiUi3!J(2}ec6+0zG0H?8(lxbo6Ldwd?ffWXGzyuNROlP>X@OePGTZUov=EN@nRfePHJM-+Tj58E2md=WQ34;LvhF@Hw#DbGQi zbBWH?nEw46+um<1x{mVT(TWf5=@ZzGezfO~_g+9P%(bSJN(iIHm|7-m%=gx!0@&Wm zbc1JiY~njQ-54nYP0E*-uqIvf2eLGkph#Kc)*{~xu4%k|J}hQrCht3-XAONC``h1; zs#FB_>}Ae&=iBW)o>F&m>vQ3_fd0TUC$hDlBZ2M`LdWOj9TE2p;klOBPLRrvu) z#;|bI>%04is%uZd^nnS%l3Uv8!^O`yoE#kB3A2E)-LMp-Uw=N$3@>@uv-MHZrs#Fw zzd}CQ5GsCtf7vNiyXa4u=Cc15ZXutlb)A5EAhgo=8@^uw)*y$dl~ZR7-LT?u#VQto z46drs3+EE1Xs(?*6)|N)mUH>*hE#Luu9^+87uLKmYj5<_iY;FmJId6{(w=x2bX?)f zg<)FZiX{3x5fOK;loi1;)`-H8Q~DCl{%q~f+QOfyq6@Tzu37MwCik)?QyK)^5V6+* zqa1UGSDXf7tx7XtxKLjWK`F2A(P@8_Zc^-8>KH1U>^iFes+#$Gs!;@S85AU6$($z{ z{B^Vd0-7&pc)u50RtNz)IGdyF+U#@^NG9FMT2eg9piag+MTKB**+swk_k?jr6wDh^ zA9nyF3BuGIOqr1djP6<@O7Gw2^0J$fHyU@p8506KRk@Lhm*9LYZBU`j?QG1)>-LBt zG#UhJqXOWNnG%%DmHz_H6q|a$OVnLg1c+;DU++JtKY4|h>O9SKBnR%Jd^}c%R?H}c z>_-oAgsy9t|AKq^M$GBBWzxMlY{#1Fvcjcq21o9xKNl^y_xdY%NZx@t@Ak? zrafjCRgKGuSLYf`UX9H)Ylwh3+$I?zbEkwRB^gxGfp*BzY4Is!94DD?WW~C&w>q=H zdhd@U80#wuSv>GEu1Cc--IN$J)t!)k=zbSCuL%MVRgrdD=@QXTl4mwOfG}u_T@Lgn z7nSpiND%!`{q`bQll%Mlb1F^1r#VDrkut}v^6l;9mKOh=k~*9F+pD!TG6kW%QRb3M za1-Y`gzDrZ0FN@>_?v2CqF)_pJ6~TY$4`iH5FfCd70#N!U24|P+nUPzLB_$5X_)&!%+7+h5GJ2JX>l;gbw0B=RpNb$&QJh3)F$2 zU(8<6+;lGvxt`b>LhV{v^wMw6caE7;c6X!|>LlopDLpSjsmL3INf;FZ@?e@)&{pSU z1jUnJj(#>d#AfhJt777Kc6F!28GsLaSwF_Y#rR|>(E;$v$;PqOCFu~m!5s^mb%Ov} z2QyDg&)?Nm-8E0*h2S#Qs(*`8EMzpaXx?r&+_jrue>}sA!kr-;X%F+DlAWLui>eiP zMDCWU@_=NJlqJ6|vG2?^j_A+NyhmcUZmTe41Y~!gYo!=h2}Pme*F8B{ALj#yhBz0= zq7`C(^w-7O5D9;Nneg4YnjDF+Yl0}2H$?0DW$ELk!JSxa^x7X!TtS8rSX>IGtOc)` z$0sKx4dvyEO7p2c~4shz62x?Z;f z^Viqv3;PzyU44DZ`LoDw>{uh!c9zMNvy0Dl5oYHy=l^oh8Oz0Tv5`r6?JT@!E>2PA z(Mt!qwF#!tf8zK57YlHo5DU(ee!a#>x{siD)tc^*e7r31S#40IM=y8nE97Gql$oTJ zZKx5~?VVl*{A#ZXvb=W{PS?bvv{KoWfLfJ}ti%*o&3cMDUN2Kq{cv)BAmDFxWFC$m z{t6#{jg@Xe3NM*)9^E2yna+vl8-LZK)gXC7_+(yJyJtSH24vniiqd2h5IMc9t7bP$w4qjM4I~IQ*?|Bh z#gk|I`=&&!92JrDI5KdV0Q2btB7qe85mZ>0=cgyD$N-?HGj_UMbop(UIU=g_%dYW6 zmx8|Y_Q-LA?-Zq{5$0DudDUdHookKV?QfPa)*h@`$1mh@KLrs(1DbBy%`yX&K!~uE8)jEQ4U5H4~&iw z1P~ojxXikNZ4T(AK?=O=)vDk8tduRm6XDUhSG{oCs~y8D>d4$0jMH>6Ul(7F0AOGo zgX<96NdDtZ=2CDBSl^VGC-?zI4UCSD@9srYbP68SW8%{g(0{pUrSx8Kss+O(KU1#K zJ}VUM4cARjNDSln#qxgM^kdlU_E%~qCiO_}%$)MjKyB9w0jTe!P-!|CDBt&-t`ng- zPxWJSygans332p^!?0dsLtz2xEU-SBHp_{?VWXf%DE{A}&xKe!(T?W{r778>vIP8= zv6F9VjPFWQZf5b%bAI56Kk0n}#YJ!&E>Vcx`D$=ZuvMePuu2MMFE7C+dh(evlY{q6 z^h64e+4AMFhBa-jZj>aW8ahs)1>687&_;{~ZzckYK>gwX)dT^=TiNIwP$5vi3Oek7 z^<_ii5WZ&6vb1+dDvBtxa-$>p`lIQbDT$1U9evDjYr$5wsQx~bEN(bkrstFXm65Py zucitSOdLUvTUtd@bS6c#5jH1LRG_z^4*J8wH6vn%@eC(wfkPUwN#B))YpRT}bz zQGw8!75;}?f192FgT#C3%M@Lb6%>fS`TJ&B7?q(+GH6U6&^R?VlawdsX!P@Sx#B7c zAL}ahPRr2OE$Ylc1T*^nG1@bC1IK=ZzOJsg-o3 zR2^$_ORzDr^0RNx8-=k(=y9l7Vs22LQG)nw_K!_ylBS~(F zWe^D=e7$D)Nig|@QU`tri*0BK+G0_P?W~VKE_yRr0T!)q98)~6!I-j$&=P898uh-+ zk_9^wmEmsfpJM8FEP_M@AF1#@49RL6<%)5Gy~+8yLhUT%3&9(=6{S zUezYYZ7v8o}~Lv1V9u2=@_S@b4a7uXJ+C(8-6YZ6%x|6{B=fkP88hv zQp=B$>9twamZSsEql}>LE?lbe3@l#Zn|sL}^YZL!q&gRK@QxLGe(iE36B!vFJ1-;B zJAd#(N+nfAEC5W9Cf*|bVtZ1oS;=Zr|q;Pd6?ZJl?#!K z%6BQ;2SsJt=rk3R#Xc5Br`!wbXCmIR`p^@2QUnaZ?X7;NuHnql=We04DO%bU?lTN) zs6YbRO5TwyYe}L$^%Ire3^CaLth2cVe{ zo1g8gOG-;^zR-|me|-CKWV#`hnLQDc=A=mLgl7c>3qmSR-qa8q-6PwD{3fawBL+ zpS8FxJA>oGz!{45=_7hb!>0dzgCZjhx+)4`2-V=}&F?qA<(h=ZBLZ6cOX5NbdNd28 zdoG?w<0?@>vS7HrJzXMG;su!jXh*0$2`!ifdNKZ+w>*1^ZHFNd z(a$58_zDkUF%`aEZJ9D-^_6dT#v*IO6du{UB>MfeH~=W+AF-xaQNlQ>LwM(#p50T* zs#9EDZ>ROfZy|i93gXm-%Uj9hMFyXock**RMhB*I_<#Q+fjnPcjaBz zSn))f&%HRPJMLkzWt=|X(!<1%?l>F@!bZ*(?$4`1G5_{pa6p7Alkh5B=(e5J`;}O4 zf)3n<|3tP}gx0&MX+}Q6AW={{r@mu)ev?eCfXGbwTe@$?>+OB3ux}c@pQbMn+U&Ml ziNSC-LJlvcm!b!)W02=Mh$9VGv-NuMRIYQnchy_51uOWrhr zGniXEEB3RW0Rp=Q0q|=kdg0wqwf?0%jtcIA@>C!7{j{hh%DoG0wu(vCt~uOL?^t#F zC>|5JXgLE*>354%O-cFakOGIb^-qp!j4VE29jvU0AaEw1J59=4y0~GPq3*PYU+2Eg zQ6(3gU`m?Y-nlQrct{SsFS0L`Hf^Kuj6%ciH@gnZllWmi8fMs+AmVyY(6fXXyE-wc0J$9N-txKn8EmE zi^gG#Mkt z*SLBzusGu2?Za!F{0fl5AouyD5*Lb>zttG&zODLi{JB52RX@O)mD@&tDu>1LXkqS+ zV(1FE$_k^*FIMj9>bksHiDV4@9CzG`BUJxzk4h8$q-h~i3|c+!KI4mkSkiP4w;0L8 zpw5#|^*m^BNq6{*gYW^w?6n4Ad+b$mH{MmXmwRsxX8!q5j4S{mQ*`5nTG_V3v9y=U z_Y}ux+#D%}`YSCM63syXBNu(<<}?4zAPznik}9bFfp4kHsWVi!gL_Fb8G}A%c(vz& zgXt45Z0=Qvg)kgHy5WB|H$( zsw#JllUvr*p1g>23~!%ucy5>i_vhZ>3dE4UgD+9BDDHIp_qMMA<37??kh~dkY%h3i z{|7vdH-A~^q?UZDuD9o>l@B}|e)3yl)pDOGSBWWxW@m3fW<~#Zx7Fjd^arpt0uf0H1`Gv7 zMb~4c-l-`m4s%Wuj|Rygh*#xkLjS?#=8ppZP>+L%^wp%%gX9-NVjTXv(~Ns& zL^z0Lr+4pqR2UK!f-4MZyJqx5%BVE7p(Q#l)swCusnc802F#E3WUrBY1`;Rgwpqo2`n8TWmtt<&l`k3BdR?(8I{2aVr-{ zXL^wV7 z?8C^x0hoU>u6hN)aPMp;n-#XXIHlAn&U_R_dEI_oH0Q7Qf(9+JBLbf0pIVyp(i=!w z+XhWp-TKhRaGFLV)$Q3lLG$L6YKDGkBLTU1X6m-HMq@&||sN?c80IjN6 zWAbuzskH8e_0NFj;(c@!m z+lDiBBcl}%ClvQ=puc~}iG_4+iU)j%g2Fjj(>ROF6gl+99Dwc63j~NJbG5{a;XeO= zmL2XWTRjD2b~!erc>|{;$re+16H_}$_p9-ITqxr&Pc>}f&>(}B2mrt-ii7k9Ezm^V ziVp+*-IKHhM1-P`lq`Y-%GmgN)VKo*{)RUY1S;qYA#~6Kfr~a#)Kx;kTsr~r&r^Mj z%r<;RK&b#L3JsuB_F%;zl7NIhbLjCEqY2w`NM&K>V`M7#5o<93HoM`^MF@gywu7Dk z-%MuIE9%mt4X#Ovar%;CEFiGdmHA3KDRdlh)fn*%%vlnr^^!R)>pGgd_1o8;Y_ivOKUQ#!|9SwIkyx#c zASTLS=Cv$1!t!SMFco2`-FdI+*2LqejT^JS2s?-HNdSJ=i65Jz=tYVM zJB@l<=sST*zbG*g2vv-kDgqTj4vyF>D%Xh15XlTjEEp1+7|Sx|F$bPBGSshr4h_jy z3?B(!SW$$Msw@EAf8*PJs-Pcj%%VUjzN~97N=qU!G6Xlee1eL~b_0BFF`?j&qHaD! zB-&hJ=%)wTbH`vomI9zz%O1un1)eJf$R55leX@!FcJIFvbW z8n^U|*;&v_tUS$h|7MEDM4&(CYD=}ll^Pag9Pr%L$^DD2=M)EyIy!uu?=&v{eZRZ{ z(im6E4BLA~+i|Ti4F1VlI8?3bt2-2jXA$%A|2)HCe6#!I+?a z^CwBfwGlt9Nxc3q8pIz72_lA`QP_Z|Sj8w*VD^QPFjNGipG{|GUyC}>=2@OW7Hr0j zVkX9>x=Z*OeM61Gr!<-qH6PDGNs|Pkemq}tplcL<6x4i5(H5nX%jrN|$%7FfxR7j7 z_rW~M0z)NMy_m1aR@JZQ!Viz3!dPZtqwf?MQcX#D5L?=M@X#IowX}49l}9U&sU#I0 z0Nb78(W4LMSzKaDs3;~QNd#ZT*Q^{`{y9gVTn5_zY@!~E!NWVaGF)lG$q}rtt!z%r z9|K>8!tuIB-+?CXZwD2TcM_rqh=Nm*gHuO}yqC8x%A34V@tD?^sF2ZN5J>CB$(3is z&bwsMlAWv#EMdEJbj}7s6$ZxQVAtF)H3P!SjxA~Ks+T``KD3((kv|saeIN7NmW<-CoL}{%&{2@H}X=sPxM4ot$hLQ8r0a4NgYbv+E$)wLLk}3TQq2Im*H-}??$6cCkVKZP3fkwB1L$Am{8qHz`9OBSHMu11$VO~>^Ou&YA@ zPWxWgqrMOy2!x=;Zv^y!;|N?vx(wipIA|Ft^ZE*@$P5-jqFr&ErO1mTB7z@)4|{Lh zb@?0+u=r+#0_ZvBIItS{H>dqk^|0brc5I5=&i#dc9(P&OEWPOyRDj=rqrOfa8O)l#3aG%(yxOnG zf!{26W5dU^#V^%LmhBeHej_+QtPSJVWIQ)H#HhD@6%uGpDrHBk%K_K`PR(NjEvJ5) z)x&Fo^_7V*!s>ob#0Zx60uL(61t?Aiy-a6wGxggN-AtlueWiy6obSsm2s%hJ&?sG8 zh36xqQmnJSoz>tl*wCH`uJRoIobdWddqgzS~V?XRcuXgds5&Bc00811Z_fe)Ube021+HA;^L!e@kEKyTO=AUt+#uW z`DD}S$_+hW_!x1b_P_6M1+Ft7!5iHcpU2c+%#4|O9`>Pw7?%o8HTlnDWK8T0Qmy?D zHk5syw>su5Gc8{$IU3P`H}|Ikw^rx`!wr;MZ+oUDTIj{Gz> zS>xd3ROF*PnunibwQ^ty5N?;3>K-3s?CiM6B+0Lhfvk|$rI0wOalG?=Y-&Ef>asGy zt+8^UoEu$vG?vHqsw%IV0K{ASk_VuVytahRC_w0pNW&xuf8K-?O^)KSN1xy` z4aY%l7hs6{8Sq784R-9wVrXYC1qYOCl<_m;c%`U9AppxDZq`#M5N#Gl%`phe0z^iU zq{OITaX@m6O4P>tC4r^ni}uNtdQ>o{Wtyu@(6oc#p3EJ1re*S8O^H#hJZ}RlyX?YJ zZ{DHDS>}p^zyIcJ%a1m>0ab3Rh);6g5g{byYj>0u+@7dF0UN>JwAp2cil2>JM<&)T zi30ELxUYvb1kzr{a*0vu8s4819&Wv94VXghTp_GVxo^Y*0BYA6y9gKv^S+Mc20df4 z{}4Mh=chCY^+yFjGP}cmOb(^w|2ehv42;EyZ2TFEFh+UDrPW|onku~D;TUNo)&V^D zc1IVfc_h(1K3WV=aHG4a^waQ(CBi=m@)R@$aOn(C)tx%G7G&UXke z&aON+(j1l+sZkM{1ukX_*DoBufI{A-D!&*U`*v#8*v28&CNA`Ep8RPuqAnKJBPb0G%rji z8h|TS0TOx4(mh(LRJ8tpip4pg%wWFU;Z{E79NbCfAWd~!$LVa~_iwFu?2;d|;Em2l z?XFuTFV(##DP)u9oIrse|H13Zv$44JUYv21-**14A)2%GREZY&_^eN+qzz+LB*!l! zDhdr(Sgn+b%`<50B9>V+(^P^NYVek%?V|;N%XEY&2}LM?ymrA5qoqPZf3t3x8RpH% zXhVv3)2nw!ci^Vx`WZKhKOG%CG>|_|Jb-pkhfG&Oaw2}1K)0Y3AJ3PHi7sm$0!U4q zqywYAIui(FxCl`pismgu$uNWhJfIDm6OGAK9ihPxEJw@T^n)N4vji;PY>q12j*u`d zrOst0y&x$f?)OP4>9(^@V;S|#C~NJOo?;>U3wk%ICZdrHU8kf=Cfc8UZWWt8B=b?J zSX{C#H&5`T>_3EjS5J^T{6)PwfdG(YM?0esVG(pr4>8($(zvda?GIWxDMizk)xNsD zY2V*R1B_Dz+L?OVLPi`HB#s)sKe!FlEaJX(1~3T8EceWscE@5rT)#D)|K!tMA&;{8 zr`}6DNw~yh!lwM=gr=G$l+*IZ_LxnMP5Q|rt7^F~{zt}6g;xtM{{_TiUYI%7)NNIf}k)?9w*VekNbesWE>H45; zd)(R1gjErv&{Eq7NOL*{Nf4@*bpvlVAiZIYCx26P?M&}*sVhbl(%B7KjOj=RIat~$ zK%(uLk;L} zfd66vva0J8gzPq{CCGhRx?hm!DxAfReShoF8Ig*M!CCsgIxD9pr>16gSjOiVG(DED ztvVgYMgY8zV|PCPSuE)RX;ijk0^5r*e?(t3oH860=Q(~t}nth6#;kmubR}@whRN_5N(}TFd!2b33vs0A≤ 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

    6$RZS4td7JG|)XvqL`>HcJB^X1y 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 EE5xq~syu4)d`B(L+WyCTAj^;Oo+l37dFw9uBPo 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%0AYtFqa`rCMQxVq5{ot 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 GR` zO>CAHdy+2x)qHNO*W zgoIG0{f z=T`&e+jngr!7<6Hml+mfHy=`m!5i4of++!ku8l=Mv$NYF{WW6M!I%*QN)`+YHqGw> zBL*OCRp+SE8}>TL;yJIqU(3-KqqeF+1AQ=+^88}O>;wVt6!V*s2a?V) zdl+rJi;$A)1kNkhutS2jw;O$4*&S=Y{vO?c7UZ>?V;ZLxEu62EAI?jDfu zP!NL|GG-HH!CKX2S65eY4jV1O@zCy}oPc8pZ}6bA2vGWYT9A+cepjs_RN(qsTYL~# zfikLPJBosY==#QzrsdYly4G9)Z_cI|hQ7*QLbc6m8EIl#O)rG-b8@VvCI5& zZaMK1@fH3$M-3L&1qF)PFhB%RUi@CD81gImKKmj6_||hnQxV2y>DP@`pOCURuT#d%H7+%i?XXz6GVufBrY*0%guL)**0wJ zqAgKf-K*~S>szlro*lA#p?e@)E~{3Gp`1WL@Wy4T2KPP$WtzMy&r&tA6kIB47`J^= z7WzL<8w4TrtVt~3^vCR-UVu?Od?ndLKWH?wm6w*5Y@V%}nITBS0+3$OfWRc6rm6QE zzoxUnl`r0&Du#q$UOv`flOcSxa=boz7jbdf8D!&s#%J$KB}o12XCIQSsUkTLHfV8$JusP6IPIJ?IbKO9$IsQ zpA^!Yvja1&m)5LoY|6PeB{h)A0kl_PsPVogLwt*kwL64%d*iY<^QiY|J|B2M4{zq4 zo+a@*v?)ub^1OXh=Q?xD7hehjsWR)CD#P}yLB{)tiL%YMo}ODike!Z=kBO&~q+xwG8y_wWOiveq zcU0*Fye=X_3GsW-ekQs*-f4SUf|!f?*)w~&y5izu*(C1f#0KUsnah9nWVbL;Q4bDy z9TqzPzI~Ui48dG5Ji=#xRFC=r5${v19qAN#buBd=82X{s!8}+M{jx&}5T$i8AG$Ja zl$%=-gVspyWkwvEnR01P)MqK3Qa1dY6OZ@B_Lc}vmmOxcmGk2n2!`4d6X$Im_?>b| z7gBO^n6MX_Os6Fv*TxSzru*`g%Z`nUOCqmln$JCyXg}o37fQ0%wUh4V)BmB){9lJ6 zr9)MN46oSaT6ECCrf(l6)ngQb^}h{fdct{xu}X!_zJ>NdpkW~W9_eWr8uG;>R&?Ft zbJ|#W{2~Kdot6_$fWSuo$jZ~=2)jUvlaiI)JG^x7jJ6c|6!PYgD0vtsr^nX-a!SgD zA+s4!@B*)96huOTd1S8V!D)^%3$hO|&twufUH^O#fk37INK{Kp8=}8?DG)LF+z!A| zT>$t8B^hUj=YFm8�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 %sc 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 Sd5xfwFjkvLpnP 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 z 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

    <2>}EF7H6OUr^^iZLX@>t5FckpKLAG!R+Mt|Y|d zDA5drS0#+4abwGwfHg6*&P*%&0Y_WT3`oYgToB&c}RB1qjk2n`ZNi1ZTGvnHRJ7}4WZfQK@C6nJF4u@h+B z$NKu}g};bH4(D5rxizN@(@l=(F3;oCx3fP!vaGD|XA7`r5Xwl&7bOL6539dNhbtBR zH$@zm1@{G3+`&V)R5Xt=w?u6i8T0q144Xr3LxT}ZYRf{uOYW3bNsOXwTS{W$;I?DE z**^3i;VLOp4Umg8Imk0sVkU}zXid0^l#=cZ73as_tC~@$i}H>){OTJJAlwv49p4pQ zXckt^6Vj0AUpzW=He9aI7g#igw8%!u3(Y6Q;L(qqm`B10)ruA=zJ&P3(Hqz{nW-@o z{;IxdYx6c6O$)Yb1E(j?wH=B z@ok%j^H93p+ik1_X)^0Myqez@8(^K$>ol;`YJejTXq!J!{{*;#N?Z5c z)gjo9!90??y9S&7OaCRHex@Tc{+2Roc5&-XsvvP5{}vawRJqiF002J|OJD#bHfQ(h zP{T7F%rpfrhKuF}A%9?DVR`ChNPdX`Q?z^{!Kd_!pjWOLkg+5N4^omH)G!1b???-* zOzUcvo4-i;qUhq(seC3J$aT02{?SWL3vb-VV!$vJT5A8iFAKz`yh@?^b___1*r_6y z&rBZ?)|n)@HDS6=HNH8qGdU7KS=b*rLdVd(98+`=>MMF5Y+}$50BeI5cYgNNdk>fk z8x%^if>^t>2%}!{yq+2Bxw?Onqe_EL80g_{>1!bm1p)xOC5+M(Xz>c1K>wFSuk*6& z2Yh_J?;K=kZXTVNPj-9T+vrFz3XAKF!6~C+h2gjj*eyW)(My31R?JU z;v@nNUHPF#K%fH=iw=~MG>KMM2bg`4eqhMcP9A0aM}e7~1ZWR0FMAT70Be)q6JH`} zYYJGN7$SF1?YmNyyIX0R58$v+ujDOJEgRLD-Pyu9wF!yxl`T|WYWPFI?7lUW2tMZ? z1CS5cyE~ROA@fTqV|zHf37yk!`NiuZBwQAR(c7Y;qK_X7ygY7Q52jZZ7UW7*ms>R~ z=(<0$Y@d^GGXk+3Nl--Y$>+VpCH+v|nHG{p{Ir zU}5c?(t01KY_aq8Ui)xda=`%;V(L;z)xX5bgPp&`Nv5G`GGhW$j4oaKlbdO=rLM5P+9<3FwWfE__-(shr= ze}8vFRHA{qSi=14kB6rxXo9qKqFIyyJ-aONMFO9TDbIX-6(?x0;FnSF8|-YC)i#gK zol*So6ALr52J`W5C*R`i43MMkRYBZ*sBl-MzRUv0n7 z4d~{41!>lP3~X#fg$l?h_d6Obnw|bAgRToEN3S(1nL%%Q7V%Y)>-Dw8g0jx-`V&7{ zE)Iux!twpgy6}eye0kNnj!2Hsv-zo#-2=}YZqi)kg`L5rS6W*7LcsEaX}&)|9LArU z!L|NaAYNnTocU$Hx`);Ari3y}R_K*MuLF|n9Tz$dRx+d3CHHG60k|Et3bA%ql?Y0+ zclY%HA7gUK5}^0L1!R-POl+y@V$vut7eMF9D9NL6t!;vGSnTn(J!c^yut6xcYgg*m zS#;-1+zj9AWn^Z+tUGSyD|ftz?w2SgzCtfN-OX0n|5w9CMMTI-N(v<=C8-0afB_#S z)~PNik~jpQiNujTlljjPxU4Pi_^@9b!6q?Hacu&~M)f#?>6* zFG2jCmyrMd)blS)hm=&ybMg1_m~jWPz#a!^=flHgzMIK`Wl&WKtm-Lg_S9c=fe5yM zfB;3j+KGvu)YRLOG?xYeMqRrPoxDm|-Y6fp;&Ax^YxCaK<&KfvsvV4O!oAAUSdRI!%r)x9mGz=`z^O8P-j zDMO>gcu${WSkpI*3pJ4Yils_SgAX{lEcU-ss`;Cv?6W`r+h%Tq_w4f`$VjdyZNhT;@!oA$#+1M1%4Vg7-pb*R zXYN>6Z|`@d{GW@_tNM64;h;}`^XgU3zl^20I5coj9)zlrwTEW^g$WH0OzXu-QzRx+gv3FrOxy1Lr|7VhxL5ueHM zzw}-h|LT29*e@#gSNQ(Mjt>E9KGM%Y%#t?H2PjZ-xKUX*}j~zEi!Nl5}&c27vM8 z0bE+$3?>yqAFx7f4ehU;xd|8ixklU}M*~_{#L)DZ9bakkDgCu}!Ixwe8*f#hC-+ zd#IwNfA9FU9v?gD1?6CdP3X_S-(o-zN%I=IyTj7=dS_J%v+jhXQOKI|c5p^Iu|ta? zn&EZaNyH{))O+~A&d%qD+i<{bgN5*`O$@)zsYtyXa6PsT{nzh!@^;@v%AYK`buHGH zKV5V@lhxVJeY0CJRQ0|5YXp|tCEnJq4Co;uhd8SY5KmEG`47eydwFEG_}nLj!gm5( zYix{RkA5JhnLm46!cP&Z`Br~%U8T3o_blU7D@#*2xo>Az4}>=EdlS9{{n~Xlo4be6 zs>Ri77y@V2dYv4eBaC~GVZCOcTGOsn2Ob)73I`HZFy`4^!(%C*Pc(f3n$>@vj z=RQ1%8p39+ou$|d=P~D5$Yt0rS7jBXz&sgGNSl?Hg@r`hBGgJ@Ac1Wes4GEw-^lV# ziEiJ_6c(aZKBqQJ>BOcJx9^F2@czct`8WIqz(at62ps|<9T!*ESvwZy$*(Ji$Mv@9 z6mqK-3(mJMU|O<4P6#fK%h%OdL7y;M0V}4RA|(cQzSWSoCW_n)470txQ@y<^)uUhv zRc5f`{eLMeDY9$?wA-QsKXYE7;Le1-K_v_f3^c}Z1vw)?v~SRKTAi7>0-A!!*?|Gc zFJ6&2%p!+ppoRnJA9LUKTR=C}*VG8jEnVTyfjX;l4rtToz)fg;PhY;d&iDJg*{^^_ zWQg|aoBbLPC`9?TIPapUhT2e)kib4)jGqAqjb9dQ5Ws?M1AWorvOj|X2)QgicnH`~ z)R~WWfcF3-=TFy5)qtVed$+&dEdp;Z`XdIoP3D|$4<`qs&dq%d70m+%E6(mTIWV(D=XxHk-vL%m zt;Y-b9|J9gt2;PyOOxCmCes#qT=gd`$OQgY`J3{>oOI6Ix>3}giLlc+t$}k)X0MXp z4fTnD!SKii`i~I2*_8@87-GF5NhO@7Z=Aaq;HiLqaxYdWNHbQ2JLf6k!y%aZbW@}` zNg#G~icZ}Q8#qrT4xMvk9opE76;nukL=>5?!#_g<%@ty57aR&9#gJBA%K@D;C{-qA_qK1^2PBLSs^G>d@d0=$b1*;b#8#n?a&TXzR?^g@Q}spH}EJ`ZxpNlPL`-jza|41i&&*Pkw6=# zfB+WMaNRw{+^qjV_cJCjk@~+BJjPtbay922S@x&DU~s^){OMhu`pfjF@Pa})n@sn}m1uKZ zzmes*%_wpNUD|C1dEn!Br;_EU+F zVXvvV6ca!wY}_LX;kb9#tfSE5g*PVDoU12Q#O~G(Pm*jnW=ddCaeFVbW7E@H{hn7r zJN*x`@K{< z7#zo@*K4u(RZxl(G*gLRk?2o+xmqoGIiHZwF}RmPND*aiUMo$hp!K7gO2f`jKSDy$ zyZJ7t3KHrS(#g(`Ih3OEo{xBH*eT(=)oW|gEcyU6#`qgT_SGxlb*?JagQbGhl$0D$ zWPAulq4$je-0E+%FqC(Tb6{$oUK^jS5m=RCNB74Meq3qAjsnZAbr#r@P*PG>c1Tdf zXY!b8-bg9G(`<1mt*n#-{*uf{_-qzkIl_S&wIaFTEdE~Q7n+z@*sxq0|5=MTQTi%V zl4=iAo6nLk1V%{OQfcVf`ebY~zwG2O+HZ{eJ9+96BD@q7D@OhwM`4JJURk}EePuL4 z-as{jTKR9+Qn9Ll2D?Hvt9tD)DiW-@Sy~I*z{3|BkKL91mMXBYj$9cT9GKvX;L zHPKyB=j@@Edw$is~ zDy2doD!O*vnH0FPXZw5uzj&@L9DRNC-LK*Xm^TLty87KXW*OmNzM&<2{L?#X-|+yV z7+!qlo;qoxrRH8}F_>i=ZCP9d2`h{`zCS4Gy4Sx6S|h$feOA&`QgR)xPeio5Np@_Ix93M zoo-I@;bEh8rv|G#S0DNX1@u)^O#aZ2l$KhOC_C0X7!Ywhj(`xS$9PM;$~7r4bNh+^ z$bQq&H|O)-*J^_q)BujwJFMTe4>a4rE1c z?1{3ok=H4I!;H7!ZK~EX$jMHuIzaht@HEl0BG>E=6M+568;49 zm}0GSRK?*+bQK_Szx>Q7N2b12f;cl~K&eh+9Nh2i5Ex<+J7{pk+BxsGr}Wn2&RJz^ zqO-gVR;y{_RPa}46{l&tp0-u>O;@K}tVyHRn55$2i;AM9GZG&Qq|FfP^6K`6rlOX+ zAbdL~c5OOV95^~nCO@D{e)q?Q=;`p~;hhf`f$w%=@}j=@dTaK(QIIbrzu|B%V4uZ# zg33O_o~(CGTF#kxl~_T===V2vArjw_U0q-QUo~-nN+ zez=YLhZ})G^g?mM$Ky{h)=8l5J6B z1WMpp?cnc(?f}SBD=fVK)V|-D0GhoBd`@{$*At4q8NBL7Al^B<*zII8>UqnF111X{ zhZ3miuX!Z(;Iz0#s^KKX|f&-iQAfw z!sen~%l;1Ms{2LT#n?ArST!}ZHTTU(Tl>l2_+R`t%Q|{`tRCkD)6=Slk#A9gZxW80 zcUQeSAI?LrX>t{#nG<)KvN{MeUD`O9|IEl|52F*&-EXZl**}1wL=5*e99{jsEGhT}p~7FPTEdWvMX7 zTz=0chtIz=l6FvLyQD3z$WcT!bh<&Rszyt!&BXzM>-~G* zzo!pCC#j*D@XoomsMO?V1o*H2S$xR;SUi=QoJ@r98VuY{r)wbEF>BysIy#+E&=1^_t5<CUxg2R+@n5eg{m0(+myEI6EtVhXtsQW@`&=<1;dLTv~v2^~`(o55cUmx1N4f zo!OOb>O;ti%JfHAO(b;;(P}{Nw|gi}F%l<996q0m!dk^FL)dL3>EU&n7mD zg$6zyV2CcTccZ4X`KX~$khu*xC?tYQEZzNjW6+JCR9@nUKDk_we;gkrxY~Q-9US%Z zNv*{!Dg>ojtOX!a&L*23KZ32Go`-KI8Ac6QyDP z5rJ}Amke@eW~|w-%(BU@qOv{3wr-#0^zZ9sM8|NeG@ZR+`VJAXlNTyiVi;CoH}fW8 z-hNxK>3l9c&Zj4VpcPr(7R8VdOT1jgc{}?xB`)r-B1Tg-Q;g1S3ZBgkooY}H{;y9a zYpZ$yn`>P9Ls^?AAugUYwZGWtmb{v&Uh^TG=AiI=NztzM7o}2==@JI{;_FY`Qwc5p zzB!A_Duq*iz@8g|7Wa;KMSn0D)1{SKr6qV0$Y=zW9USdO!aZyeTx45|iP~l0l%f83 za6Q`)WS2lzMqde@J;zDIzgwyN*7rvB(D|yQ9SwpeBwHDs(u>|Afen3%O-xh;L*OHS zYHATl-eJqasu-?&_9aLEqdJVgo#b33zn81&$B#foR+5)DvRiIFxAE=U+5Wx{9$s6; z+T<6UA`Gt)U&pDa`EqJ3dWygSC$JfBxBE;9d*Oc;@!mcFXLQ zXu-ICn%uzG+*tN&e$K!(!L~#Z;FLl;bPj=Hc#|ZVS(-%*k zlidH1Kk=I$)WH0{hzFqpIXZ@=;LiR@Gjns`PxDGBD7t`aoPPD(N%hU`L(p3eqz|I1 z;AqsbsTkf4b8cP9RctC7+Ps<-Z3RPF;F@TLy{hMTv(H@mWD$tct4fOcxKFh6I=|2C z`+m#A9phQHA7&Vz%SCj#oXXRAmeaMv+gQJ9RA1c^0grG7680EwKZ0Y4y&+7(#@*M}h3|%~GV`FOv*d|MMPP0x9j0 zTlB&#gPz+3ZsWd5)aB7#q?9-QkjL4%xUG*|injRW-L<)@ZCrjvNQe|jPN|0-Yk$Kb zCqtJ}+Ryb8{UjRxn>!15`H+7v-}No9w>vG(P)<&*4iWfTgKP5U_x)I_??LN*^DBNE zU6$*RVDL=@8?dbTun`bZ`gM#y+@c2qA&Q>YjS)n17&Rce?2uYY)qq#sK0C)IvQhI|lx*1rV9PEHEsFo|zID;{9Y0fx ztx0}y&ODzK_kLkAGVpin2Q4ehlfM2_c3GMQ_UoL(|8oD|3tEg= znBbofW$ZU{VDvQ{`d=?fRQdUo>X6!dqg~%^5;axP&FS1m@M@x)OR7c9z$&74`nCGoIWsW?O97(BY$0s8J00TRk4%{q3A3 zO2$hm&Qw2dcwk-9CAE)|q^6%2N*KjQo`CXp6q(7Wy)NJeSXGaV9QKv| zd{&mfj(+{5hAu6iT2C2IilRvP{kCV1?&HrP3PHE~(GO?HwjO`oMByD^@j5OFm0UQK zSDsS+1t=8JM~lQwl(8dDK@{lcCrkDI`3m?snhL`Ra}yBP{&44ryi5e9Z2pW>AOFwm zSxh?pUt>%f6)WnkE0m@2S{DsnHdwfB?Tc!1e4VPW5?X~n&vx=?H}$JrIWei^xDs5vPN-tK`(?#)94GfQ^j%$_?1$){ouYyr|8f)%F1-`fBkI zCoJ-@03Fnzf|KH{K76w*phXQC;oyDO0EpA}%G5s!6g={q1UHTch9guWLb}rn#lILj zqh*D3E4*GuwAf4=*XNh{%`Fb<2OYQ!4uDZGQN;hp?gI&?s@@wlO?gsVt`wo7s2Le? zb>iDVYZAl6-KV%;{nB&lq@b$aUn|l}15X7R+@d97Af9?;Gn&9Dxons6ofhgdE(p6E zFUjNF;svw1iq`Hk?VkIvm3k?2PZnCpZ)6iK(yh&srj)hZ0>typRNJvPi**e~ z$5x%ZG6kOfW&j?=ws%iHmGXd=6ySQ@QG4M;wtD}$UDIonV14$L#g1E(9KT$!wDqmTN z7fe3O7X1SGHch6;zTIkGd6v&YlGtHz@v%$00*Q&_KT+xs0$hj6`31)6Kwij-C9sbH z>4K5aKhJn5E0PH5Eg_Q))fb4Qh=?o8y75-g_cP7sz>e|zHh0f4F$p$mmt@aPNpM7Ar)?-S-Z>0OI6Q6Axf|)rOQ!K4_L+upG#?(`ZZ<=& zWJOF%rL%#PpZ)#B^QQ?yud#UJE9WXf_6XsB+7aWkQnIl+;0KM|8!Ie4O0d{*u{=m& zR!-e7ko7N#jx6K`50NjynHVle&e}lcjmWeC#8XE2xha#9W?=v4Dy3W37)}K*MUr=t z*7R_t00C4pm3+oQAXKE(*@_!C(D*0b*CBpvWUd)xo?mWNA5niA@`fID;?{t{CvPa= z$~l?m;M(seVt@RJyowMA9PZTTHyO*eR`v!&d}!(DBHMEiQMm?xuUY<;Dg{p%E#OWE z6kKst=}F>Ug!vBI)|sRu0LDp8(L7&n2b93iGHMLIZHUf!VXqE2G^%7l6pTOWjtt;D zV^gANT@mCoO`v}L<+;Q|x&6*}ivVz8;59X1#^U^pxOZ2VD15E`xeF=N>E$W~2lRb7Cu zmRK!K#Zv4flbv-J5AZYD>Vpo~DoQeMU86$zjBX5U<{$)YZJsx-f9~u|d?Ntk=H^yU zY_PhjWYYw)1}iG|yqh{toFE9~Lm8fp)?-fY*>R7X*R5|fG{`vCym-MSQ~>(ceC(DZ z0^5Gt5zSe$^eSNIY(hc;wd{J(aR@%M;%RvhI}5lx?4uc?rtPZfVQGXvcQ1t9Cqv;aRUQnlq0J9L3xFqNhFX*4)GD zXCEU9P|K5^KIMY(BGI2q^|&!Y-anGt*j~Su1pi7j&i(e9W3-5pMMi{;P0s)U_Z;Qo zAFBdXS}KG4X-Bqd@yU_&f*bi$27 z#x^VYp1%jniFEcp_OuFt$p?j0S=#=d(!w#aR10z$0PbW`60#VzXS?P?bLLE_Aw336 z>{Mm`80;_+u(vtMlv{t$YQ6=xX?x=TAzE4w4xs7!r(d{9*wjd)H;VSEo%amk0Mh-{ zgP9Mo)yb%!NUXL!DH4|S+_j!K;3g4J>4)CwJeKkw!SrD)H)P*nBR~v&U~Vl^W&Evi zL537Sh%1POVjdMxXlZIvhHrGIUR+a-k&F2yjGFa2EH5vwjs@fkIIOQD;C2 zeHamgxzm-h@vc3VjS*|+(OuQwFACBE)l^mKV#~`{IWzYI<8wibSjcak3$${5UI(U& zL^>k4;^Otp_>ocCw69B!>}lXFBAU&&q$h2&nHVHijxiM{CsF=PeEx!-^9v3R3&TE6 zd;)w?(a{D5q`hAa(YN7L*SKVDzgKE+ z%&Xr(d~|)SO&EYavig1-1PCF<_1@{CLO@yHQ& zlKVH%**qx`^O~H=Fiidsg4_a0NP1a?xB_Yj?&Gajc z@lJsA^*-sHn~}vUD}=K%5#R=;$nOGXae$LpMvCYUgD7Dj zc8#9Fj39+DN85s%#Gmi8`b*#jbeUy;3}THwBMkZ*CU#CW1}zSh4R6qLCWC#-fnlWn zpf8+#j95KP%)X-n2PmET2GH2BurQi{`zJ#-UoGWx9Sg|Z>94r>fiYw2eE5V>wB!EK z-5E~!GzjXOmD_v-foVbe-mI=Jxx74EU_h&=YINyQQ@e$O)UwVhiyk-}4$$rp0!9`* zc`&*b%OyCR!_3N8Bcz%dF2Aa32;#?uEfC`4>o)nM2rn<+#i%$e9CF}64l_VaW4~^> zw|V7(q|Wr#9up&@m6cUnbm|?Hp6#HBPe21u9+aFJV<#03b}8~;qcs%3wADvOk_N&O zGVROLlaqm>x#vtz=e+QPz*sabhU|twD0+`M0=D{@!Yo^*JyEW!FB1Ii4^~O}nuv>6 z8oqXf0D$Nb@8J?=J^s2^2YXv!Qg1B8JN!MNH1s6hzA3~zfS8}Htt~p}v8700BVx2I zdQq982kXHJ&VL5htVjR&N^*WmX6%ALeOZ8FRMgM&s_U4WTM}cKd}iq_0vw#N%+dq` z7cVbOY*UjaP|O{jOk&Q2FQDIjyh9U>D_AOrotGQd61(sDZ}bl)@(0SU{?$3-x7OVV zxKMiJj~Wt$pRgXiAx$+7-e}D+Eh;P=@M>Q0l(-gCD^Y{v8LK1AN}k7y)Hv^PsEM*X zE?s20D8_}csu>30|9}h5+|*PLMU3=Do%CaGq?Gt=K~RT}@tmSA+^@WeNoT1I^Yikw z!0FqMaW{?yTiUM+Y#H*x0MJ=cX{p0VZIe`Wr!H;w9bb^9oMiUkvkj!qGUW#xY#{si&z@9SDv9v0z$Gm+S#avGy_OEH zqN@6K?UVFuxBvIL#WFf*=3u?sL{od(GhsVpCeX=@l0uDZ7^lfl`q{<0B~K~49&|gS zB-j9M!?Fs%ScCRexoBNxj0*6DRcbm1M`ymkln?pFjI;oNFHwq5&7ROdO4)U4RzO1cf7b*Y> zXST~2P#)XUKjnlCS_F-L&MQ0nI6LgOqoz=S@qo2xyL8dbrTXRlb$k!{V9|mbGr2JU zc5By4GTC`~*E)EEK8v2oOnw?QJ(aHmK+M2 zZSO)Pcmb*E?D`Q8=B}aPy^`@hxQ!%se;*o4{Is&t?D0v;(dpsC9r>dj0qDcI^v12l zB#(u>By&IT!|Xw14%dX+c4__6#@<0mrd>a-hh6{;Xr2JV%j=z4Ch58WPrb9eJb;1$ z@qGQ=AqO=$6Bq4}0(R?2=g)&pkTw9~q^_=>s!>!@qNS!LL{U*%T21nGa!O06i+Je` z9G$5@um$BHGXZ18B4gAy-Lqa z_hvmm7b?ee)eux}qIT;drU6&O3}uBk@bX6jR;vcJA~oz~j>&q@(FyZvh=HlWq1MWFc2;hiiA!!@rDFgTe#zBvyTGB)?-I&7qIwXnS{+V(NB^ob> zDyeu_IU}vB#Uy7#1{lIv&dqZ^_=gwx?<&m80vkkKG#o+~$;Cqe_QnycPXL_!(_!489BsO5~jE6>PDeH1{u;}ejF&)<$oTep=dW&<>Oe2>JG zr>69m8#$$=AQes?eYnF2b(i=-Ew?QXgz^>3XRpBKuxO82nFnJJ=f=DS(+9Hf3;MKq z8*~iCVsry~aFdGxq*i)u8Nr%(3*KJ6SAU&ozTVv9;ClLSXbu9bv^KY=u(QYVRG^u9 z-`Ud`xNzp^hdLnV*BUE3v9;&%U>980qeZ~M>F6zN(EhUjG9R{!;x|QVISK!F!KZ4* z(Zeq-?d(&;09Hx!Er9Hnu4QMF^7nF*#Ua)q#c;ZbP&G_U-@JUX{(vY*!?Q0Uo)bf= z>Xg~l-G^*x>fc`O>_;Bml$HkIk2iqzs0KEkZ)3nTh_qDS30&2Y(Ed|zXvr4%!7L>o zP=DY@mO@H{3{y2bJ3DD&pFE*(v;pc4xE3gjNC3oGHc-6NH0Nj^n9?)2vQSXe(b-v# zYiQt#izB@0h<~M|^i^Cqksv7pZ2g~CLPKSWMWruX6rY*HUOKk3Fx@+Mt|qAc zC+Ek%bFO5+6ryS2Ap4twc(zhK*=G>qk1{z41cG?8zFAt_4_(?u2lR9y#+y$;{5JXJ zd6XIEfpR079}($&U15tX1P2~U7EwEX1@vcp@%R&2cno~{-y0Rk-B1YR-2dK5761fy z{y&kBlQnLZv@Wf?WQzk$_#67Mg!`uzFQ1E&=gMawnt+`E9E^>qU4{&AiEE_@XZahJ>J|GXUBY!>5EgH~>&*yuNY8!c_M`-7{Lk7&?0 zK&a7`tRYk$EQ^z>Y3i?iyCxF&H1u}zzkaROc6Be;Ot`2d88-dhiYIiuW7pYl>PJ(s zoXO$ud8EQ>BEBYZUQ_52F2_El7KMq}ksmaux28_`dP(22*{wb%d4DX(EPDki`c-r% zv#>hq!+=TsPQmUG$=-KYIMQ^h+RP&=P3(AFBo@fxjuKs#@@*j_6h!2pZz{$2x`0}- z&AuB-Q}0=yxXZW&rYo+Q*6X2vhpi6Uo)R$0UQaK#P^!8o2 z)xFXnPUG6x!3h)K$M&e`Pg>hf4td!cY$hzC^4(h=&0#A?{k?wYd+(Yu(HNAtzF9Ea zAick!x;l9vdSsMP>-KtrR9(p2D%c1jLuseKfMc!pgZ~W`q&KkAiw^7Tk3!U2)hv7M zDCXyX#J26-(~`UOjC(I2rZo!*9 ze0bT;R?TD#FICl^4=$yZN8fF$tN;*UAjGIpP?49PzZ)QjclzLm{MowNIpe}jMwr#0 z)ojmS*Ch{Gv1NXfuI~ATEngED27M9i*Qkyrx55*jvi@w@nqH L1uwmQ_s{ ma5 或 ma10" +- "RSI < 30" +- "放量(量比 > 2)" + +### 模式 B:历史窗口(filter_history) +当规则涉及以下任何时序/回溯逻辑时使用: +- "最近 N 天内出现过涨停/金叉/某信号" +- "涨停后的第 X 天" +- "上次涨停的收盘价"、"前高"、"前低" +- "连续 N 天阴跌/阳线" +- 任何需要多天数据才能判断的条件 +- 任何用户自定义的、需要从历史数据中计算的概念 + +## 你必须完成的全部内容 + +输出完整的 Python 策略文件,包含: +1. META(含 params、scoring) +2. ENTRY_SIGNALS / EXIT_SIGNALS(根据方向和策略逻辑选择) +3. STOP_LOSS / MAX_HOLD_DAYS +4. ALERTS +5. RULES(中文逐条列出核心逻辑) +6. filter() 或 filter_history() 函数 + +### 模式 A 模板 + +```python +"""策略描述""" +import polars as pl + +META = { + "id": "english_id", + "name": "用户给的名称", + "description": "用户给的描述", + "params": [ + {"id": "param_id", "label": "中文名", "type": "float", "default": 2.0, "min": 0.5, "max": 10.0, "step": 0.1}, + ], + "scoring": { + "momentum_60d": 0.4, "vol_ratio_5d": 0.3, "change_pct": 0.3, + }, + "order_by": "score", + "descending": True, + "limit": 100, +} + +ENTRY_SIGNALS = ["signal_broken_board_recovery"] +EXIT_SIGNALS = ["signal_ma20_breakdown"] +STOP_LOSS = -0.05 +MAX_HOLD_DAYS = 20 +ALERTS = [] + +RULES = """ +1. 规则一 +2. 规则二 +3. 规则三 +""" + +def filter(df: pl.DataFrame, params: dict) -> pl.Expr: + param_val = params.get("param_id", 2.0) + return ( + ((pl.col("close") > pl.col("ma5")) | (pl.col("close") > pl.col("ma10"))) + & pl.col("signal_broken_board_recovery").fill_null(False) + & (pl.col("vol_ratio_5d") >= param_val) + ) +``` + +### 模式 B 模板 + +```python +"""策略描述""" +import polars as pl + +META = { + "id": "english_id", + "name": "用户给的名称", + "description": "用户给的描述", + "params": [ + {"id": "param_id", "label": "中文名", "type": "float", "default": 2.0, "min": 0.5, "max": 10.0, "step": 0.1}, + ], + "scoring": { + "momentum_60d": 0.4, "vol_ratio_5d": 0.3, "change_pct": 0.3, + }, + "order_by": "score", + "descending": True, + "limit": 100, +} + +LOOKBACK_DAYS = 8 # 根据策略需要的最大回看天数设置 + +ENTRY_SIGNALS = ["signal_broken_board_recovery"] +EXIT_SIGNALS = ["signal_ma20_breakdown"] +STOP_LOSS = -0.05 +MAX_HOLD_DAYS = 20 +ALERTS = [] + +RULES = """ +1. 规则一(包含时序逻辑) +2. 规则二 +3. 规则三 +""" + +def filter_history(df: pl.DataFrame, params: dict) -> pl.DataFrame: + if df.is_empty() or "date" not in df.columns: + return df + + down_pct = float(params.get("prev_down_pct", -0.02)) + vol_ratio = float(params.get("volume_ratio", 1.2)) + tolerance = float(params.get("reversal_tolerance", 0.005)) + latest = df["date"].max() + hist = ( + df.sort(["symbol", "date"]) + .with_columns([ + pl.col("open").shift(1).over("symbol").alias("_prev_open"), + pl.col("high").shift(1).over("symbol").alias("_prev_high"), + pl.col("close").shift(1).over("symbol").alias("_prev_close"), + pl.col("volume").shift(1).over("symbol").alias("_prev_volume"), + pl.col("change_pct").shift(1).over("symbol").alias("_prev_change_pct"), + ]) + ) + return hist.filter(pl.col("date") == latest).filter( + (pl.col("_prev_close") < pl.col("_prev_open")) + & (pl.col("_prev_change_pct") <= down_pct) + & (pl.col("close") > pl.col("open")) + & (pl.col("close") > pl.col("_prev_open")) + & (pl.col("close") >= pl.col("_prev_high") * (1 - tolerance)) + & (pl.col("volume") >= pl.col("_prev_volume") * vol_ratio) + & ((pl.col("close") > pl.col("ma5")) | (pl.col("close") > pl.col("ma10"))) + ) +``` + +如果是极复杂状态机,Polars 表达式很难清楚表达时,才使用 `partition_by("symbol")` + `to_dicts()` 逐股票分析。 + +## 信号匹配指南(参考) + +根据用户的选股方向和策略逻辑,从可用信号中选择合适的买入/卖出信号。信号列仅供参考,不强求使用。 + +| 方向 | 推荐买入信号 | 推荐卖出信号 | +|------|-------------|-------------| +| 做多 | signal_n_day_high, signal_ma20_breakout, signal_ma_golden_5_20, signal_ma_golden_20_60, signal_macd_golden, signal_boll_breakout_upper, signal_limit_up, signal_limit_down_recovery | signal_ma20_breakdown, signal_macd_dead, signal_n_day_low | +| 做空 | signal_n_day_low, signal_boll_breakdown_lower | signal_n_day_high, signal_ma_golden_5_20 | +| 监控 | 两者都选 | 两者都选 | + +## 规则 + +1. 用户可能调节的数值阈值通过 `META["params"]` 暴露,filter()/filter_history() 中用 `params.get()` 读取;公式常数、固定窗口边界不必强行参数化 +2. 信号列使用 `.fill_null(False)` 处理空值 +3. `filter()` 只返回 `pl.Expr`,`filter_history()` 返回筛选后的 `DataFrame` +4. scoring 权重总和 = 1.0 +5. `name` 使用用户输入,`description` 写一句简洁摘要 +6. **必须生成 RULES**:格式 `RULES = """\n1. 规则一\n2. 规则二\n3. 规则三\n"""`,用中文逐条列出核心筛选逻辑(至少 3 条),这是用户审阅策略的唯一依据,务必准确完整 +7. **贴合用户需求**:不要为了使用已有字段而改变用户本意。用户说"前高"就是"前高",需要自己算就自己算;用户说"最近涨停后的收盘价"就从历史数据中找,不要用其他近似值替代 +8. **输出前自我检查**:确认 RULES 已生成、Python 语法正确、括号匹配、引号闭合 +9. **优先 Polars**:不要默认生成逐行/逐股 Python 循环;能用表达式、窗口、聚合、join 完成时就用 Polars 语法 +10. 直接输出 Python 代码,不要解释文字 diff --git a/docs/strategy-builder-step2.md b/docs/strategy-builder-step2.md new file mode 100644 index 0000000..551ef72 --- /dev/null +++ b/docs/strategy-builder-step2.md @@ -0,0 +1,34 @@ +# 步骤 2:修改策略任意部分 + +你是A股量化策略工程师。根据用户指令修改策略代码的任意部分。 + +## 输入格式 + +分两部分提供: +1. 当前策略的完整 Python 代码 +2. 用户的修改指令(自然语言) + +## 输出要求 + +只输出修改后的完整 Python 代码,不要解释。 + +## 你应该做的事 + +- 增/删/改参数 → 更新 META["params"],同步修改 filter() +- 调整信号 → 更新 ENTRY_SIGNALS / EXIT_SIGNALS +- 修改止损/持有 → 更新 STOP_LOSS / MAX_HOLD_DAYS +- 增减告警 → 更新 ALERTS +- 调整评分 → 更新 META["scoring"],权重总和保持 100 +- 修改筛选逻辑 → 更新 filter();如果新增/删除了历史回溯逻辑,同步改为或移除 filter_history() 与 LOOKBACK_DAYS + +## 规则 + +1. 保持策略文件结构完整,不丢失任何已有字段(包括 RULES) +2. 删除参数后 filter() 中用原 default 值代替 +3. 新增参数要有 type、label、default、min、max、step +4. 删除信号时 ENTRY_SIGNALS / EXIT_SIGNALS 至少保留一个 +5. 如果修改了筛选逻辑,同步更新 RULES 中的对应条目 +6. 用户可能调节的阈值才需要放入 META["params"];公式常数、固定窗口边界不必强行参数化 +7. 优先使用 Polars 表达式、窗口函数、聚合和 join,不要默认改成逐行/逐股 Python 循环 +8. **输出前自我检查**:完整通读修改后的代码,确认 Python 语法正确、括号匹配、引号闭合、缩进一致。有错误直接修正再输出。 +9. 直接输出完整 Python 代码 diff --git a/docs/strategy-example.md b/docs/strategy-example.md new file mode 100644 index 0000000..7e0cca2 --- /dev/null +++ b/docs/strategy-example.md @@ -0,0 +1,153 @@ +# 两步创建示例:强势反包策略 + +本文演示从零创建一个自定义策略的完整流程。 + +--- + +## Step 1:填写规则 + +用户在创建对话框填写: + +| 字段 | 填写内容 | +|------|---------| +| 名称 | **强势反包** | +| 描述 | 筛选前日阴线下跌、今日放量阳线反包的短线强势股 | +| 方向 | 做多 | +| 规则 | 前一交易日为明显阴线且跌幅不低于2%,今日阳线收盘反包前一日实体,收盘价接近或高于前一日高点,成交量较前一日放大1.2倍以上,当前 close > ma5 或 close > ma10;使用 filter_history,并优先用 Polars shift/with_columns/filter 实现。 | + +点击「AI 生成」,AI 返回完整策略代码(含参数、信号、评分、告警): + +```python +"""强势反包 — 前日阴线下跌 + 今日放量阳线反包""" +import polars as pl + +META = { + "id": "strong_reversal", + "name": "强势反包", + "description": "筛选前日阴线下跌、今日放量阳线反包的短线强势股", + "tags": ["反包", "短线", "放量"], + "basic_filter": { + "price_min": 3, + "price_max": 200, + "market_cap_min": 10e8, + "amount_min": 0.5e8, + "exclude_st": True, + "exclude_new_days": 30, + }, + "params": [ + { + "id": "prev_down_pct", + "label": "前日最大跌幅", + "type": "float", + "default": -0.02, + "min": -0.10, + "max": -0.005, + "step": 0.005, + }, + { + "id": "volume_ratio", + "label": "成交量放大倍数", + "type": "float", + "default": 1.2, + "min": 1.0, + "max": 5.0, + "step": 0.1, + }, + { + "id": "reversal_tolerance", + "label": "反包容忍误差", + "type": "float", + "default": 0.005, + "min": 0.0, + "max": 0.03, + "step": 0.005, + }, + ], + "scoring": { + "change_pct": 0.4, + "vol_ratio_5d": 0.3, + "momentum_5d": 0.3, + }, + "order_by": "score", + "descending": True, + "limit": 100, +} + +LOOKBACK_DAYS = 2 + +ENTRY_SIGNALS = ["signal_broken_board_recovery"] +EXIT_SIGNALS = ["signal_ma20_breakdown"] +STOP_LOSS = -0.05 +MAX_HOLD_DAYS = 10 +ALERTS = [ + {"field": "signal_broken_board_recovery", "message": "反包信号"}, +] + +RULES = """ +1. 前一交易日为阴线,且跌幅不小于设定阈值 +2. 今日为阳线,收盘价收复前一日开盘价并接近或突破前一日高点 +3. 今日成交量较前一日明显放大,且收盘价站上 MA5 或 MA10 +""" + + +def filter_history(df: pl.DataFrame, params: dict) -> pl.DataFrame: + if df.is_empty() or "date" not in df.columns: + return df + + down_pct = float(params.get("prev_down_pct", -0.02)) + vol_ratio = float(params.get("volume_ratio", 1.2)) + tolerance = float(params.get("reversal_tolerance", 0.005)) + latest = df["date"].max() + hist = ( + df.sort(["symbol", "date"]) + .with_columns([ + pl.col("open").shift(1).over("symbol").alias("_prev_open"), + pl.col("high").shift(1).over("symbol").alias("_prev_high"), + pl.col("close").shift(1).over("symbol").alias("_prev_close"), + pl.col("volume").shift(1).over("symbol").alias("_prev_volume"), + pl.col("change_pct").shift(1).over("symbol").alias("_prev_change_pct"), + ]) + ) + return hist.filter(pl.col("date") == latest).filter( + (pl.col("_prev_close") < pl.col("_prev_open")) + & (pl.col("_prev_change_pct") <= down_pct) + & (pl.col("close") > pl.col("open")) + & (pl.col("close") > pl.col("_prev_open")) + & (pl.col("close") >= pl.col("_prev_high") * (1 - tolerance)) + & (pl.col("volume") >= pl.col("_prev_volume") * vol_ratio) + & ((pl.col("close") > pl.col("ma5")) | (pl.col("close") > pl.col("ma10"))) + ) +``` + +--- + +## Step 2:预览 + 指令修改 + +进入第二步,显示完整的策略预览和指令输入框。 + +用户如果觉得反包条件太严格,可以输入「把前日跌幅放宽到 -1.5%,反包前高允许 1% 误差」→ 点 AI 修改。AI 更新 `params` 默认值和 `filter_history()` 逻辑。 + +确认无误后点「保存策略」→ 策略池中出现。 + +--- + +## 后续使用 + +打开策略配置,**基础参数**和**策略参数**分别独立: + +``` +┌─ 配置:强势反包 ──────────────────────────┐ +│ 名称 [强势反包 ] 显示上限 [30]│ +│ │ +│ 📊 基础参数 [启用 ●] │ +│ 价格 [3]~[200]元 排除ST、新股 │ +│ 最低成交额 [5000万] │ +│ │ +│ ⚙ 策略参数 │ +│ 前日最大跌幅 [-0.02] │ +│ 成交量放大倍数 [1.2] │ +│ 反包容忍误差 [0.005] │ +│ │ +│ ⭐ 评分权重 📈 交易参数 │ +└────────────────────────────────────────────┘ +``` diff --git a/docs/strategy-guide.md b/docs/strategy-guide.md new file mode 100644 index 0000000..9403f13 --- /dev/null +++ b/docs/strategy-guide.md @@ -0,0 +1,332 @@ +# 策略开发指南 + +本文档是策略开发的完整参考。人类开发者参考它编写策略,AI 读取它生成策略代码。 + +## 1. 策略文件格式 + +每个策略是一个 Python 文件,放在以下目录: + +- 内置策略: `backend/app/strategy/builtin/` +- 自定义策略: `data/strategies/custom/`,建议文件名和 ID 使用 `custom_时间戳` +- AI 生成策略: `data/strategies/ai/`,文件名和 ID 使用 `ai_时间戳` + +## 2. 文件结构模板 + +```python +"""策略简短描述""" +import polars as pl + +META = { + "id": "strategy_id", # 英文ID, 唯一, 文件名同名;自定义策略建议 custom_时间戳 + "name": "策略中文名", # 显示名称 + "description": "策略详细描述", # 一句话说明策略逻辑 + "tags": ["标签1", "标签2"], # 分类标签 + + # 基础过滤参数 (Stage 1, 引擎统一处理) + "basic_filter": { + "price_min": 5, # 最低价格 + "price_max": 200, # 最高价格 + "market_cap_min": 20e8, # 最小总市值 (元) + "amount_min": 1e8, # 最小成交额 (元) + "exclude_st": True, # 排除 ST/*ST/退市 + "exclude_new_days": 60, # 排除上市N天内新股 + }, + + # 策略参数 (Stage 2, filter() 使用, 前端渲染为表单) + # 用户可能调节的阈值通过 params 暴露;公式常数、固定窗口边界不必强行参数化 + "params": [ + { + "id": "param_id", # 参数ID, filter() 中 params.get("param_id") + "label": "参数显示名", # 前端显示 + "type": "float", # float | int | select + "default": 2.0, # 默认值 + "min": 0.5, # 最小值 (float/int) + "max": 10.0, # 最大值 (float/int) + "step": 0.1, # 步长 + # select 类型用 options: + # "options": ["ma5", "ma10", "ma20", "ma60"], + }, + ], + + # 评分权重 (用于排序, 权重总和 = 1.0) + "scoring": { + "momentum_60d": 0.4, + "vol_ratio_5d": 0.3, + "change_pct": 0.3, + }, + + "order_by": "score", # 排序字段, 通常用 "score" + "descending": True, # True = 从高到低 + "limit": 100, # 最多返回条数 +} + +# 买入信号 (回测 + 监控用, 对应 enriched 表的信号列名) +ENTRY_SIGNALS = ["signal_broken_board_recovery"] + +# 卖出信号 +EXIT_SIGNALS = ["signal_ma20_breakdown"] + +# 止损 (负数, 如 -0.08 = -8%) +STOP_LOSS = -0.08 + +# 最长持有天数 +MAX_HOLD_DAYS = 20 + +# 提醒条件 (监控用) +ALERTS = [ + {"field": "signal_broken_board_recovery", "message": "反包信号"}, + {"field": "rsi_14", "op": ">", "value": 80, "message": "RSI超买预警"}, +] + + +# 策略规则(人类可读,逐条编号,至少 3 条) +RULES = """ +1. 规则描述一 +2. 规则描述二 +3. 规则描述三 +""" + +def filter(df: pl.DataFrame, params: dict) -> pl.Expr: + """策略核心过滤逻辑。 + + df: Stage 1 基础过滤后的 enriched 数据 + params: META.params 中定义的参数值 (用户可在前端覆盖) + + 返回: Polars 布尔表达式 (pl.Expr) + """ + vol_min = params.get("vol_ratio_min", 2.0) + return ( + ((pl.col("close") > pl.col("ma5")) | (pl.col("close") > pl.col("ma10"))) + & pl.col("signal_broken_board_recovery").fill_null(False) + & (pl.col("vol_ratio_5d") >= vol_min) + ) +``` + +### 历史窗口策略(filter_history) + +普通 `filter()` 只接收当前日期的单日数据。当策略需要以下逻辑时,必须使用 `filter_history()`: + +- "最近 N 天内出现过某个事件"(如涨停、金叉) +- "某个事件发生后的第 X 天"(如涨停后放量下跌) +- "前高 / 前低 / 上次某事件的价格"等需要回溯历史的自定义字段 +- 任何需要多日数据才能计算的时序逻辑 + +**不需要** `filter_history()` 的场景:只用当日指标列做比较(如 close > ma60、rsi_14 < 30)。 + +```python +LOOKBACK_DAYS = 8 # 回看交易日数,根据策略需要设置 + +def filter_history(df: pl.DataFrame, params: dict) -> pl.DataFrame: + """df 包含目标日期之前 LOOKBACK_DAYS 个交易日的数据(所有股票混合)。 + 每行包含 symbol, date 及所有指标列/信号列。 + + 返回值: 筛选后的 DataFrame,引擎会最终保留目标日期行。 + """ + if df.is_empty() or "date" not in df.columns: + return df + + down_pct = float(params.get("prev_down_pct", -0.02)) + vol_ratio = float(params.get("volume_ratio", 1.2)) + tolerance = float(params.get("reversal_tolerance", 0.005)) + latest = df["date"].max() + + # 示例: 前日明显阴线下跌,今日放量阳线反包前日实体 + hist = ( + df.sort(["symbol", "date"]) + .with_columns([ + pl.col("open").shift(1).over("symbol").alias("_prev_open"), + pl.col("high").shift(1).over("symbol").alias("_prev_high"), + pl.col("close").shift(1).over("symbol").alias("_prev_close"), + pl.col("volume").shift(1).over("symbol").alias("_prev_volume"), + pl.col("change_pct").shift(1).over("symbol").alias("_prev_change_pct"), + ]) + ) + + return hist.filter(pl.col("date") == latest).filter( + (pl.col("_prev_close") < pl.col("_prev_open")) + & (pl.col("_prev_change_pct") <= down_pct) + & (pl.col("close") > pl.col("open")) + & (pl.col("close") > pl.col("_prev_open")) + & (pl.col("close") >= pl.col("_prev_high") * (1 - tolerance)) + & (pl.col("volume") >= pl.col("_prev_volume") * vol_ratio) + & ((pl.col("close") > pl.col("ma5")) | (pl.col("close") > pl.col("ma10"))) + ) +``` + +**关键要点:** +- `LOOKBACK_DAYS` 决定引擎加载多少天的数据,设为策略逻辑需要的最大回看天数 +- 优先使用 Polars 的 `with_columns`、`over("symbol")`、`group_by`、`join`、`filter` 实现历史逻辑,避免把数据转成 Python list/dict 循环 +- 只有遇到表达式难以描述的复杂状态机时,才使用 `partition_by("symbol")` + `to_dicts()` 逐股票分析 +- 返回的 DataFrame 必须只包含目标日期行,通过 `pl.col("date") == latest` 过滤 +- 未声明 `filter_history()` 的策略走普通 `filter()` 路径,不受影响 + +## 3. 常用指标列(参考,可直接使用) + +以下列在数据中已预计算,可直接引用。**但如果这些列无法满足策略需求,可以不用,自行在 `filter_history()` 中基于 enriched 表的数据(已复权,含所有指标列和信号列)计算任何需要的字段。** + +### 价格相关 + +| 列名 | 类型 | 说明 | +|------|------|------| +| open, high, low, close | float | OHLCV 开高低收 | +| prev_close | float | 昨收价 | +| change_pct | float | 涨跌幅 (如 0.032 = +3.2%) | +| change_amount | float | 涨跌额 | +| amount | float | 成交额 | +| amplitude | float | 振幅 | + +### 均线 + +| 列名 | 说明 | +|------|------| +| ma5, ma10, ma20, ma30, ma60 | 简单移动均线 | +| ema5, ema10, ema20, ema30, ema60 | 指数移动均线 | + +### 技术指标 + +| 列名 | 说明 | +|------|------| +| macd_dif | MACD DIF 线 | +| macd_dea | MACD DEA 线 | +| macd_hist | MACD 柱状 | +| boll_upper, boll_lower | 布林带上/下轨 | +| kdj_k, kdj_d, kdj_j | KDJ 指标 | +| rsi_6, rsi_14, rsi_24 | RSI 相对强弱 | +| atr_14 | 平均真实波幅 | + +### 量能 + +| 列名 | 说明 | +|------|------| +| volume | 成交量 | +| vol_ma5, vol_ma10 | 成交量均线 | +| vol_ratio_5d | 5日量比 | +| turnover_rate | 换手率 | + +### 动量与波动 + +| 列名 | 说明 | +|------|------| +| momentum_5d / 10d / 20d / 30d / 60d | N日涨幅 | +| annual_vol_20d | 20日年化波动率 | +| high_60d, low_60d | 60日最高/最低价 | + +### 涨跌停 + +| 列名 | 说明 | +|------|------| +| consecutive_limit_ups | 连续涨停天数 | +| consecutive_limit_downs | 连续跌停天数 | + +## 4. 常用信号列(参考) + +信号列是布尔值,使用时用 `.fill_null(False)` 处理空值。同样仅供参考,不要求必须使用。 + +信号列是布尔值,**必须**使用 `.fill_null(False)` 处理空值。 + +| 列名 | 方向 | 说明 | +|------|------|------| +| signal_ma_golden_5_20 | 买入 | MA5 上穿 MA20 | +| signal_ma_dead_5_20 | 卖出 | MA5 下穿 MA20 | +| signal_ma_golden_20_60 | 买入 | MA20 上穿 MA60 | +| signal_macd_golden | 买入 | MACD 金叉 | +| signal_macd_dead | 卖出 | MACD 死叉 | +| signal_ma20_breakout | 买入 | 突破 MA20 | +| signal_ma20_breakdown | 卖出 | 跌破 MA20 | +| signal_n_day_high | 买入 | 60日新高 | +| signal_n_day_low | 卖出 | 60日新低 | +| signal_boll_breakout_upper | 中性 | 突破布林上轨 | +| signal_boll_breakdown_lower | 中性 | 跌破布林下轨 | +| signal_volume_surge | 中性 | 放量 | +| signal_limit_up | 买入 | 涨停 | +| signal_limit_down | 卖出 | 跌停 | +| signal_limit_down_recovery | 买入 | 跌停翘板 | + +## 5. 规则 + +1. `filter()` 必须返回 `pl.Expr` (用 `&` `|` 组合布尔表达式);`filter_history()` 返回筛选后的 `DataFrame` +2. 信号列使用 `.fill_null(False)` 处理空值 +3. 用户可能调节的数值阈值通过 `params` 暴露;公式常数、固定窗口边界、一次性内部变量不必强行参数化 +4. `scoring` 权重总和必须为 1.0 +5. 遵循 A 股 T+1 规则 (当日买入次日才能卖出) +6. 只允许 `import polars as pl`,禁止 import 其他模块 +7. 禁止使用 `open()`, `exec()`, `eval()`, `os`, `sys`, `subprocess` +8. **贴合用户需求优先**:第3/4节的指标列和信号列仅供参考,能用则用;如果用户需求需要自定义计算(如"前高""上次涨停价""N日内某个事件后X天"),直接在 `filter_history()` 中自行设计和计算,不需要局限于已有列 +9. `filter_history()` 中优先用 Polars 向量化语法;仅在复杂状态机无法清晰表达时,才用 `partition_by("symbol")` 逐股票分析 + +## 6. 策略示例 + +### 强势反包 + +```python +"""强势反包 — 前日阴线下跌 + 今日放量阳线反包""" +import polars as pl + +META = { + "id": "strong_reversal", + "name": "强势反包", + "description": "前一日明显阴线下跌,今日放量阳线收复前一日阴线实体", + "tags": ["反包", "短线", "放量"], + "basic_filter": { + "price_min": 3, "price_max": 200, + "market_cap_min": 10e8, "amount_min": 0.5e8, + "exclude_st": True, "exclude_new_days": 30, + }, + "params": [ + {"id": "prev_down_pct", "label": "前日最大跌幅", "type": "float", + "default": -0.02, "min": -0.10, "max": -0.005, "step": 0.005}, + {"id": "volume_ratio", "label": "成交量放大倍数", "type": "float", + "default": 1.2, "min": 1.0, "max": 5.0, "step": 0.1}, + {"id": "reversal_tolerance", "label": "反包容忍误差", "type": "float", + "default": 0.005, "min": 0.0, "max": 0.03, "step": 0.005}, + ], + "scoring": {"change_pct": 0.4, "vol_ratio_5d": 0.3, "momentum_5d": 0.3}, + "order_by": "score", "descending": True, "limit": 100, +} + +LOOKBACK_DAYS = 2 + +ENTRY_SIGNALS = ["signal_broken_board_recovery"] +EXIT_SIGNALS = ["signal_ma20_breakdown"] +STOP_LOSS = -0.05 +MAX_HOLD_DAYS = 10 +ALERTS = [{"field": "signal_broken_board_recovery", "message": "反包信号"}] + +RULES = """ +1. 前一交易日为阴线,且跌幅不小于设定阈值 +2. 今日为阳线,收盘价收复前一日开盘价并接近或突破前一日高点 +3. 今日成交量较前一日明显放大,且收盘价站上 MA5 或 MA10 +""" + +def filter_history(df: pl.DataFrame, params: dict) -> pl.DataFrame: + if df.is_empty() or "date" not in df.columns: + return df + + down_pct = float(params.get("prev_down_pct", -0.02)) + vol_ratio = float(params.get("volume_ratio", 1.2)) + tolerance = float(params.get("reversal_tolerance", 0.005)) + latest = df["date"].max() + hist = ( + df.sort(["symbol", "date"]) + .with_columns([ + pl.col("open").shift(1).over("symbol").alias("_prev_open"), + pl.col("high").shift(1).over("symbol").alias("_prev_high"), + pl.col("close").shift(1).over("symbol").alias("_prev_close"), + pl.col("volume").shift(1).over("symbol").alias("_prev_volume"), + pl.col("change_pct").shift(1).over("symbol").alias("_prev_change_pct"), + ]) + ) + return hist.filter(pl.col("date") == latest).filter( + (pl.col("_prev_close") < pl.col("_prev_open")) + & (pl.col("_prev_change_pct") <= down_pct) + & (pl.col("close") > pl.col("open")) + & (pl.col("close") > pl.col("_prev_open")) + & (pl.col("close") >= pl.col("_prev_high") * (1 - tolerance)) + & (pl.col("volume") >= pl.col("_prev_volume") * vol_ratio) + & ((pl.col("close") > pl.col("ma5")) | (pl.col("close") > pl.col("ma10"))) + ) +``` + +## 7. 完整示例 + +见 [strategy-example.md](./strategy-example.md) — 从零创建强势反包策略的三步完整演示。 diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 0000000..dfa9518 --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,5 @@ +node_modules +dist +.vite +*.log +.DS_Store diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..f10434c --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,19 @@ + + + + + + + + TF-Stocks-Panel · Quant Terminal + + + + + + + +

    + + + diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..10f423c --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,42 @@ +{ + "name": "tf-stocks-panel-frontend", + "private": true, + "version": "0.1.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "preview": "vite preview", + "lint": "eslint ." + }, + "dependencies": { + "@dnd-kit/core": "^6.3.1", + "@dnd-kit/sortable": "^10.0.0", + "@dnd-kit/utilities": "^3.2.2", + "@tanstack/react-query": "^5.55.0", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "echarts": "^5.5.0", + "echarts-for-react": "^3.0.2", + "framer-motion": "^11.5.0", + "lightweight-charts": "^4.2.0", + "lucide-react": "^0.439.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.26.0", + "tailwind-merge": "^2.5.2" + }, + "devDependencies": { + "@types/node": "^25.9.3", + "@types/react": "^18.3.5", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.3.1", + "autoprefixer": "^10.4.20", + "postcss": "^8.4.45", + "tailwindcss": "^3.4.10", + "tailwindcss-animate": "^1.0.7", + "typescript": "^5.5.4", + "vite": "^5.4.3" + }, + "packageManager": "pnpm@9.10.0" +} diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml new file mode 100644 index 0000000..ed7d8c7 --- /dev/null +++ b/frontend/pnpm-lock.yaml @@ -0,0 +1,1917 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@dnd-kit/core': + specifier: ^6.3.1 + version: 6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@dnd-kit/sortable': + specifier: ^10.0.0 + version: 10.0.0(@dnd-kit/core@6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + '@dnd-kit/utilities': + specifier: ^3.2.2 + version: 3.2.2(react@18.3.1) + '@tanstack/react-query': + specifier: ^5.55.0 + version: 5.100.11(react@18.3.1) + class-variance-authority: + specifier: ^0.7.0 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + echarts: + specifier: ^5.5.0 + version: 5.6.0 + echarts-for-react: + specifier: ^3.0.2 + version: 3.0.6(echarts@5.6.0)(react@18.3.1) + framer-motion: + specifier: ^11.5.0 + version: 11.18.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + lightweight-charts: + specifier: ^4.2.0 + version: 4.2.3 + lucide-react: + specifier: ^0.439.0 + version: 0.439.0(react@18.3.1) + react: + specifier: ^18.3.1 + version: 18.3.1 + react-dom: + specifier: ^18.3.1 + version: 18.3.1(react@18.3.1) + react-router-dom: + specifier: ^6.26.0 + version: 6.30.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + tailwind-merge: + specifier: ^2.5.2 + version: 2.6.1 + devDependencies: + '@types/node': + specifier: ^25.9.3 + version: 25.9.3 + '@types/react': + specifier: ^18.3.5 + version: 18.3.29 + '@types/react-dom': + specifier: ^18.3.0 + version: 18.3.7(@types/react@18.3.29) + '@vitejs/plugin-react': + specifier: ^4.3.1 + version: 4.7.0(vite@5.4.21(@types/node@25.9.3)) + autoprefixer: + specifier: ^10.4.20 + version: 10.5.0(postcss@8.5.15) + postcss: + specifier: ^8.4.45 + version: 8.5.15 + tailwindcss: + specifier: ^3.4.10 + version: 3.4.19 + tailwindcss-animate: + specifier: ^1.0.7 + version: 1.0.7(tailwindcss@3.4.19) + typescript: + specifier: ^5.5.4 + version: 5.9.3 + vite: + specifier: ^5.4.3 + version: 5.4.21(@types/node@25.9.3) + +packages: + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.3': + resolution: {integrity: sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.29.2': + resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.3': + resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-transform-react-jsx-self@7.27.1': + resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.27.1': + resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + + '@dnd-kit/accessibility@3.1.1': + resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==} + peerDependencies: + react: '>=16.8.0' + + '@dnd-kit/core@6.3.1': + resolution: {integrity: sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@dnd-kit/sortable@10.0.0': + resolution: {integrity: sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==} + peerDependencies: + '@dnd-kit/core': ^6.3.0 + react: '>=16.8.0' + + '@dnd-kit/utilities@3.2.2': + resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==} + peerDependencies: + react: '>=16.8.0' + + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@remix-run/router@1.23.2': + resolution: {integrity: sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==} + engines: {node: '>=14.0.0'} + + '@rolldown/pluginutils@1.0.0-beta.27': + resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} + + '@rollup/rollup-android-arm-eabi@4.60.4': + resolution: {integrity: sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.60.4': + resolution: {integrity: sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.60.4': + resolution: {integrity: sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.60.4': + resolution: {integrity: sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.60.4': + resolution: {integrity: sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.60.4': + resolution: {integrity: sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.60.4': + resolution: {integrity: sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.60.4': + resolution: {integrity: sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.60.4': + resolution: {integrity: sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.60.4': + resolution: {integrity: sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.60.4': + resolution: {integrity: sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-loong64-musl@4.60.4': + resolution: {integrity: sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.60.4': + resolution: {integrity: sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-musl@4.60.4': + resolution: {integrity: sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.60.4': + resolution: {integrity: sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.60.4': + resolution: {integrity: sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.60.4': + resolution: {integrity: sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.60.4': + resolution: {integrity: sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.60.4': + resolution: {integrity: sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openbsd-x64@4.60.4': + resolution: {integrity: sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.60.4': + resolution: {integrity: sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.60.4': + resolution: {integrity: sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.60.4': + resolution: {integrity: sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.60.4': + resolution: {integrity: sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.60.4': + resolution: {integrity: sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==} + cpu: [x64] + os: [win32] + + '@tanstack/query-core@5.100.11': + resolution: {integrity: sha512-lmE0994apShXPj8CUxgx4ch5yUJhE9k/+tVwihBvPOyerACWdBocfFg24t8+0RhtlTd7tEgchDkhlCxNssvDxw==} + + '@tanstack/react-query@5.100.11': + resolution: {integrity: sha512-J0f9s5x3LE1450nNNfYx+e/n0DMa0uOBdFJUy5r0RvmsXd4nB/n0rbHtHI1vYXhikNFan+wf51p6Tmp4c8ucrg==} + peerDependencies: + react: ^18 || ^19 + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/node@25.9.3': + resolution: {integrity: sha512-603BddQMv3pUcr4U2dhujk83N2tTDVr/34wII2B6bJy6g+8WD6yUb11jszNs0gdi4PesVWl7ABt8nYMVpnLUcg==} + + '@types/prop-types@15.7.15': + resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} + + '@types/react-dom@18.3.7': + resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==} + peerDependencies: + '@types/react': ^18.0.0 + + '@types/react@18.3.29': + resolution: {integrity: sha512-ch0qJdr2JY0r04NXSprbK6TXOgnaJ1Tz23fm5W+z0/CBah6BSBc3n96h7K9GOtwh0HrilNWHIBzE1Ko4Dcw/Wg==} + + '@vitejs/plugin-react@4.7.0': + resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + + autoprefixer@10.5.0: + resolution: {integrity: sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + baseline-browser-mapping@2.10.31: + resolution: {integrity: sha512-MujYO3eP72uvmSE0i4wltsodRfIpZATP3jvzRNRGGxgzId7aVocVJJV3nf01qnzzKFGxQVC9bpWxl5cjxTr/7Q==} + engines: {node: '>=6.0.0'} + hasBin: true + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + + caniuse-lite@1.0.30001793: + resolution: {integrity: sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + + echarts-for-react@3.0.6: + resolution: {integrity: sha512-4zqLgTGWS3JvkQDXjzkR1k1CHRdpd6by0988TWMJgnvDytegWLbeP/VNZmMa+0VJx2eD7Y632bi2JquXDgiGJg==} + peerDependencies: + echarts: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 + react: ^15.0.0 || >=16.0.0 + + echarts@5.6.0: + resolution: {integrity: sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==} + + electron-to-chromium@1.5.361: + resolution: {integrity: sha512-Q6Hts7N9FnJc5LeGRINFvLhCI9xZmNtTDe5ZbcVezQz7cU4a8Aua3GH1b8J2XY8Al9PF+OCwYqhgsOOheMdvkA==} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + fancy-canvas@2.1.0: + resolution: {integrity: sha512-nifxXJ95JNLFR2NgRV4/MxVP45G9909wJTEKz5fg/TZS20JJZA6hfgRVh/bC9bwl2zBtBNcYPjiBE4njQHVBwQ==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + fraction.js@5.3.4: + resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + + framer-motion@11.18.2: + resolution: {integrity: sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + hasown@2.0.3: + resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} + engines: {node: '>= 0.4'} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-core-module@2.16.2: + resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + jiti@1.21.7: + resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + lightweight-charts@4.2.3: + resolution: {integrity: sha512-5kS/2hY3wNYNzhnS8Gb+GAS07DX8GPF2YVDnd2NMC85gJVQ6RLU6YrXNgNJ6eg0AnWPwCnvaGtYmGky3HiLQEw==} + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lucide-react@0.439.0: + resolution: {integrity: sha512-PafSWvDTpxdtNEndS2HIHxcNAbd54OaqSYJO90/b63rab2HWYqDbH194j0i82ZFdWOAcf0AHinRykXRRK2PJbw==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + motion-dom@11.18.1: + resolution: {integrity: sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==} + + motion-utils@11.18.1: + resolution: {integrity: sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + node-releases@2.0.46: + resolution: {integrity: sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==} + engines: {node: '>=18'} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + + postcss-import@15.1.0: + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + + postcss-js@4.1.0: + resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + + postcss-nested@6.2.0: + resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-selector-parser@6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + engines: {node: ^10 || ^12 || >=14} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + react-dom@18.3.1: + resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} + peerDependencies: + react: ^18.3.1 + + react-refresh@0.17.0: + resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} + engines: {node: '>=0.10.0'} + + react-router-dom@6.30.3: + resolution: {integrity: sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + + react-router@6.30.3: + resolution: {integrity: sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + + react@18.3.1: + resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} + engines: {node: '>=0.10.0'} + + read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + resolve@1.22.12: + resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} + engines: {node: '>= 0.4'} + hasBin: true + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rollup@4.60.4: + resolution: {integrity: sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + scheduler@0.23.2: + resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + size-sensor@1.0.3: + resolution: {integrity: sha512-+k9mJ2/rQMiRmQUcjn+qznch260leIXY8r4FyYKKyRBO/s5UoeMAHGkCJyE1R/4wrIhTJONfyloY55SkE7ve3A==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + sucrase@3.35.1: + resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + tailwind-merge@2.6.1: + resolution: {integrity: sha512-Oo6tHdpZsGpkKG88HJ8RR1rg/RdnEkQEfMoEk2x1XRI3F1AxeU+ijRXpiVUF4UbLfcxxRGw6TbUINKYdWVsQTQ==} + + tailwindcss-animate@1.0.7: + resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + + tailwindcss@3.4.19: + resolution: {integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==} + engines: {node: '>=14.0.0'} + hasBin: true + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} + engines: {node: '>=12.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + tslib@2.3.0: + resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@7.24.6: + resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + vite@5.4.21: + resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + zrender@5.6.1: + resolution: {integrity: sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==} + +snapshots: + + '@alloc/quick-lru@5.2.0': {} + + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.3': {} + + '@babel/core@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.29.2 + '@babel/parser': 7.29.3 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.1': + dependencies: + '@babel/parser': 7.29.3 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.28.6': + dependencies: + '@babel/compat-data': 7.29.3 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.2 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.28.6': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.28.6': {} + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.29.2': + dependencies: + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + + '@babel/parser@7.29.3': + dependencies: + '@babel/types': 7.29.0 + + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/template@7.28.6': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.3 + '@babel/types': 7.29.0 + + '@babel/traverse@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.3 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@dnd-kit/accessibility@3.1.1(react@18.3.1)': + dependencies: + react: 18.3.1 + tslib: 2.8.1 + + '@dnd-kit/core@6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@dnd-kit/accessibility': 3.1.1(react@18.3.1) + '@dnd-kit/utilities': 3.2.2(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + tslib: 2.8.1 + + '@dnd-kit/sortable@10.0.0(@dnd-kit/core@6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': + dependencies: + '@dnd-kit/core': 6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@dnd-kit/utilities': 3.2.2(react@18.3.1) + react: 18.3.1 + tslib: 2.8.1 + + '@dnd-kit/utilities@3.2.2(react@18.3.1)': + dependencies: + react: 18.3.1 + tslib: 2.8.1 + + '@esbuild/aix-ppc64@0.21.5': + optional: true + + '@esbuild/android-arm64@0.21.5': + optional: true + + '@esbuild/android-arm@0.21.5': + optional: true + + '@esbuild/android-x64@0.21.5': + optional: true + + '@esbuild/darwin-arm64@0.21.5': + optional: true + + '@esbuild/darwin-x64@0.21.5': + optional: true + + '@esbuild/freebsd-arm64@0.21.5': + optional: true + + '@esbuild/freebsd-x64@0.21.5': + optional: true + + '@esbuild/linux-arm64@0.21.5': + optional: true + + '@esbuild/linux-arm@0.21.5': + optional: true + + '@esbuild/linux-ia32@0.21.5': + optional: true + + '@esbuild/linux-loong64@0.21.5': + optional: true + + '@esbuild/linux-mips64el@0.21.5': + optional: true + + '@esbuild/linux-ppc64@0.21.5': + optional: true + + '@esbuild/linux-riscv64@0.21.5': + optional: true + + '@esbuild/linux-s390x@0.21.5': + optional: true + + '@esbuild/linux-x64@0.21.5': + optional: true + + '@esbuild/netbsd-x64@0.21.5': + optional: true + + '@esbuild/openbsd-x64@0.21.5': + optional: true + + '@esbuild/sunos-x64@0.21.5': + optional: true + + '@esbuild/win32-arm64@0.21.5': + optional: true + + '@esbuild/win32-ia32@0.21.5': + optional: true + + '@esbuild/win32-x64@0.21.5': + optional: true + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.1 + + '@remix-run/router@1.23.2': {} + + '@rolldown/pluginutils@1.0.0-beta.27': {} + + '@rollup/rollup-android-arm-eabi@4.60.4': + optional: true + + '@rollup/rollup-android-arm64@4.60.4': + optional: true + + '@rollup/rollup-darwin-arm64@4.60.4': + optional: true + + '@rollup/rollup-darwin-x64@4.60.4': + optional: true + + '@rollup/rollup-freebsd-arm64@4.60.4': + optional: true + + '@rollup/rollup-freebsd-x64@4.60.4': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.60.4': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.60.4': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.60.4': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.60.4': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.60.4': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.60.4': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.60.4': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.60.4': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.60.4': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.60.4': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.60.4': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.60.4': + optional: true + + '@rollup/rollup-linux-x64-musl@4.60.4': + optional: true + + '@rollup/rollup-openbsd-x64@4.60.4': + optional: true + + '@rollup/rollup-openharmony-arm64@4.60.4': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.60.4': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.60.4': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.60.4': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.60.4': + optional: true + + '@tanstack/query-core@5.100.11': {} + + '@tanstack/react-query@5.100.11(react@18.3.1)': + dependencies: + '@tanstack/query-core': 5.100.11 + react: 18.3.1 + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.29.3 + '@babel/types': 7.29.0 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.29.0 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.29.3 + '@babel/types': 7.29.0 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.29.0 + + '@types/estree@1.0.8': {} + + '@types/node@25.9.3': + dependencies: + undici-types: 7.24.6 + + '@types/prop-types@15.7.15': {} + + '@types/react-dom@18.3.7(@types/react@18.3.29)': + dependencies: + '@types/react': 18.3.29 + + '@types/react@18.3.29': + dependencies: + '@types/prop-types': 15.7.15 + csstype: 3.2.3 + + '@vitejs/plugin-react@4.7.0(vite@5.4.21(@types/node@25.9.3))': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) + '@rolldown/pluginutils': 1.0.0-beta.27 + '@types/babel__core': 7.20.5 + react-refresh: 0.17.0 + vite: 5.4.21(@types/node@25.9.3) + transitivePeerDependencies: + - supports-color + + any-promise@1.3.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.2 + + arg@5.0.2: {} + + autoprefixer@10.5.0(postcss@8.5.15): + dependencies: + browserslist: 4.28.2 + caniuse-lite: 1.0.30001793 + fraction.js: 5.3.4 + picocolors: 1.1.1 + postcss: 8.5.15 + postcss-value-parser: 4.2.0 + + baseline-browser-mapping@2.10.31: {} + + binary-extensions@2.3.0: {} + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.28.2: + dependencies: + baseline-browser-mapping: 2.10.31 + caniuse-lite: 1.0.30001793 + electron-to-chromium: 1.5.361 + node-releases: 2.0.46 + update-browserslist-db: 1.2.3(browserslist@4.28.2) + + camelcase-css@2.0.1: {} + + caniuse-lite@1.0.30001793: {} + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + + clsx@2.1.1: {} + + commander@4.1.1: {} + + convert-source-map@2.0.0: {} + + cssesc@3.0.0: {} + + csstype@3.2.3: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + didyoumean@1.2.2: {} + + dlv@1.1.3: {} + + echarts-for-react@3.0.6(echarts@5.6.0)(react@18.3.1): + dependencies: + echarts: 5.6.0 + fast-deep-equal: 3.1.3 + react: 18.3.1 + size-sensor: 1.0.3 + + echarts@5.6.0: + dependencies: + tslib: 2.3.0 + zrender: 5.6.1 + + electron-to-chromium@1.5.361: {} + + es-errors@1.3.0: {} + + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + + escalade@3.2.0: {} + + fancy-canvas@2.1.0: {} + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + fraction.js@5.3.4: {} + + framer-motion@11.18.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + motion-dom: 11.18.1 + motion-utils: 11.18.1 + tslib: 2.8.1 + optionalDependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + gensync@1.0.0-beta.2: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + hasown@2.0.3: + dependencies: + function-bind: 1.1.2 + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-core-module@2.16.2: + dependencies: + hasown: 2.0.3 + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + jiti@1.21.7: {} + + js-tokens@4.0.0: {} + + jsesc@3.1.0: {} + + json5@2.2.3: {} + + lightweight-charts@4.2.3: + dependencies: + fancy-canvas: 2.1.0 + + lilconfig@3.1.3: {} + + lines-and-columns@1.2.4: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lucide-react@0.439.0(react@18.3.1): + dependencies: + react: 18.3.1 + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.2 + + motion-dom@11.18.1: + dependencies: + motion-utils: 11.18.1 + + motion-utils@11.18.1: {} + + ms@2.1.3: {} + + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + nanoid@3.3.12: {} + + node-releases@2.0.46: {} + + normalize-path@3.0.0: {} + + object-assign@4.1.1: {} + + object-hash@3.0.0: {} + + path-parse@1.0.7: {} + + picocolors@1.1.1: {} + + picomatch@2.3.2: {} + + picomatch@4.0.4: {} + + pify@2.3.0: {} + + pirates@4.0.7: {} + + postcss-import@15.1.0(postcss@8.5.15): + dependencies: + postcss: 8.5.15 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.12 + + postcss-js@4.1.0(postcss@8.5.15): + dependencies: + camelcase-css: 2.0.1 + postcss: 8.5.15 + + postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.15): + dependencies: + lilconfig: 3.1.3 + optionalDependencies: + jiti: 1.21.7 + postcss: 8.5.15 + + postcss-nested@6.2.0(postcss@8.5.15): + dependencies: + postcss: 8.5.15 + postcss-selector-parser: 6.1.2 + + postcss-selector-parser@6.1.2: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-value-parser@4.2.0: {} + + postcss@8.5.15: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + queue-microtask@1.2.3: {} + + react-dom@18.3.1(react@18.3.1): + dependencies: + loose-envify: 1.4.0 + react: 18.3.1 + scheduler: 0.23.2 + + react-refresh@0.17.0: {} + + react-router-dom@6.30.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + '@remix-run/router': 1.23.2 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-router: 6.30.3(react@18.3.1) + + react-router@6.30.3(react@18.3.1): + dependencies: + '@remix-run/router': 1.23.2 + react: 18.3.1 + + react@18.3.1: + dependencies: + loose-envify: 1.4.0 + + read-cache@1.0.0: + dependencies: + pify: 2.3.0 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.2 + + resolve@1.22.12: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.16.2 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.1.0: {} + + rollup@4.60.4: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.60.4 + '@rollup/rollup-android-arm64': 4.60.4 + '@rollup/rollup-darwin-arm64': 4.60.4 + '@rollup/rollup-darwin-x64': 4.60.4 + '@rollup/rollup-freebsd-arm64': 4.60.4 + '@rollup/rollup-freebsd-x64': 4.60.4 + '@rollup/rollup-linux-arm-gnueabihf': 4.60.4 + '@rollup/rollup-linux-arm-musleabihf': 4.60.4 + '@rollup/rollup-linux-arm64-gnu': 4.60.4 + '@rollup/rollup-linux-arm64-musl': 4.60.4 + '@rollup/rollup-linux-loong64-gnu': 4.60.4 + '@rollup/rollup-linux-loong64-musl': 4.60.4 + '@rollup/rollup-linux-ppc64-gnu': 4.60.4 + '@rollup/rollup-linux-ppc64-musl': 4.60.4 + '@rollup/rollup-linux-riscv64-gnu': 4.60.4 + '@rollup/rollup-linux-riscv64-musl': 4.60.4 + '@rollup/rollup-linux-s390x-gnu': 4.60.4 + '@rollup/rollup-linux-x64-gnu': 4.60.4 + '@rollup/rollup-linux-x64-musl': 4.60.4 + '@rollup/rollup-openbsd-x64': 4.60.4 + '@rollup/rollup-openharmony-arm64': 4.60.4 + '@rollup/rollup-win32-arm64-msvc': 4.60.4 + '@rollup/rollup-win32-ia32-msvc': 4.60.4 + '@rollup/rollup-win32-x64-gnu': 4.60.4 + '@rollup/rollup-win32-x64-msvc': 4.60.4 + fsevents: 2.3.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + scheduler@0.23.2: + dependencies: + loose-envify: 1.4.0 + + semver@6.3.1: {} + + size-sensor@1.0.3: {} + + source-map-js@1.2.1: {} + + sucrase@3.35.1: + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + commander: 4.1.1 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.7 + tinyglobby: 0.2.16 + ts-interface-checker: 0.1.13 + + supports-preserve-symlinks-flag@1.0.0: {} + + tailwind-merge@2.6.1: {} + + tailwindcss-animate@1.0.7(tailwindcss@3.4.19): + dependencies: + tailwindcss: 3.4.19 + + tailwindcss@3.4.19: + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.3 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.7 + lilconfig: 3.1.3 + micromatch: 4.0.8 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.1.1 + postcss: 8.5.15 + postcss-import: 15.1.0(postcss@8.5.15) + postcss-js: 4.1.0(postcss@8.5.15) + postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.15) + postcss-nested: 6.2.0(postcss@8.5.15) + postcss-selector-parser: 6.1.2 + resolve: 1.22.12 + sucrase: 3.35.1 + transitivePeerDependencies: + - tsx + - yaml + + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + tinyglobby@0.2.16: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + ts-interface-checker@0.1.13: {} + + tslib@2.3.0: {} + + tslib@2.8.1: {} + + typescript@5.9.3: {} + + undici-types@7.24.6: {} + + update-browserslist-db@1.2.3(browserslist@4.28.2): + dependencies: + browserslist: 4.28.2 + escalade: 3.2.0 + picocolors: 1.1.1 + + util-deprecate@1.0.2: {} + + vite@5.4.21(@types/node@25.9.3): + dependencies: + esbuild: 0.21.5 + postcss: 8.5.15 + rollup: 4.60.4 + optionalDependencies: + '@types/node': 25.9.3 + fsevents: 2.3.3 + + yallist@3.1.1: {} + + zrender@5.6.1: + dependencies: + tslib: 2.3.0 diff --git a/frontend/postcss.config.js b/frontend/postcss.config.js new file mode 100644 index 0000000..2e7af2b --- /dev/null +++ b/frontend/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/frontend/public/favicon.svg b/frontend/public/favicon.svg new file mode 100644 index 0000000..57db8fa --- /dev/null +++ b/frontend/public/favicon.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/components/CandlestickChart.tsx b/frontend/src/components/CandlestickChart.tsx new file mode 100644 index 0000000..8652938 --- /dev/null +++ b/frontend/src/components/CandlestickChart.tsx @@ -0,0 +1,154 @@ +import { useEffect, useRef } from 'react' +import { + createChart, + CrosshairMode, + type IChartApi, + type ISeriesApi, + type CandlestickData, + type HistogramData, +} from 'lightweight-charts' + +export interface OHLC { + date: string + open: number + high: number + low: number + close: number + volume?: number +} + +export function fmtBigNum(v: number): string { + if (v >= 1_000_000_000_000) return `${(v / 1_000_000_000_000).toFixed(2)}万亿` + if (v >= 100_000_000) return `${(v / 100_000_000).toFixed(2)}亿` + if (v >= 10_000) return `${(v / 10_000).toFixed(0)}万` + return v.toFixed(0) +} + +const THEME = { + background: 'transparent', + textColor: '#A1A1AA', + gridColor: 'rgba(255,255,255,0.04)', + borderColor: '#27272A', + bull: '#F04438', + bear: '#12B76A', + volBull: 'rgba(240,68,56,0.4)', + volBear: 'rgba(18,183,106,0.4)', +} + +interface Props { + data: OHLC[] + height?: number +} + +export function CandlestickChart({ data, height = 480 }: Props) { + const containerRef = useRef(null) + const chartRef = useRef(null) + const candleRef = useRef | null>(null) + const volRef = useRef | null>(null) + + useEffect(() => { + if (!containerRef.current) return + const el = containerRef.current + + const chart = createChart(el, { + width: el.clientWidth, + height, + layout: { + background: { color: THEME.background }, + textColor: THEME.textColor, + fontFamily: 'JetBrains Mono, monospace', + fontSize: 11, + }, + grid: { + vertLines: { color: THEME.gridColor }, + horzLines: { color: THEME.gridColor }, + }, + crosshair: { + mode: CrosshairMode.Normal, + vertLine: { labelVisible: false }, + horzLine: { labelVisible: false }, + }, + rightPriceScale: { borderColor: THEME.borderColor }, + timeScale: { + borderColor: THEME.borderColor, + timeVisible: false, + secondsVisible: false, + }, + }) + + // Candlestick — occupies top 80% via default price scale + const candle = chart.addCandlestickSeries({ + upColor: THEME.bull, + downColor: THEME.bear, + borderUpColor: THEME.bull, + borderDownColor: THEME.bear, + wickUpColor: THEME.bull, + wickDownColor: THEME.bear, + lastValueVisible: false, + priceLineVisible: false, + }) + + // Volume — separate price scale, squeezed to bottom 20% + const volume = chart.addHistogramSeries({ + priceFormat: { type: 'volume' }, + priceScaleId: 'volume', + lastValueVisible: false, + priceLineVisible: false, + }) + chart.priceScale('volume').applyOptions({ + scaleMargins: { top: 0.8, bottom: 0 }, + }) + + chartRef.current = chart + candleRef.current = candle + volRef.current = volume + + const ro = new ResizeObserver(() => { + chart.applyOptions({ width: el.clientWidth }) + }) + ro.observe(el) + + return () => { + ro.disconnect() + chart.remove() + chartRef.current = null + candleRef.current = null + volRef.current = null + } + }, [height]) + + useEffect(() => { + if (!chartRef.current || !candleRef.current || !volRef.current || data.length === 0) return + + candleRef.current.setData( + data.map(d => ({ + time: d.date as any, + open: d.open, + high: d.high, + low: d.low, + close: d.close, + })) as CandlestickData[], + ) + + volRef.current.setData( + data.map(d => ({ + time: d.date as any, + value: d.volume ?? 0, + color: d.close >= d.open ? THEME.volBull : THEME.volBear, + })) as HistogramData[], + ) + + const ts = chartRef.current.timeScale() + if (data.length > 60) { + const startIdx = data.length - 60 + ts.setVisibleRange({ + from: data[startIdx].date as any, + to: data[data.length - 1].date as any, + }) + } else { + ts.fitContent() + } + }, [data]) + + return
    +} diff --git a/frontend/src/components/ColumnCustomizer.tsx b/frontend/src/components/ColumnCustomizer.tsx new file mode 100644 index 0000000..814dcd7 --- /dev/null +++ b/frontend/src/components/ColumnCustomizer.tsx @@ -0,0 +1,24 @@ +import { ListColumnCustomizer } from '@/components/ListColumnCustomizer' +import { COLUMN_GROUPS, type ColumnConfig } from '@/lib/watchlist-columns' + +interface ColumnCustomizerProps { + columns: ColumnConfig[] + onChange: (columns: ColumnConfig[]) => void + open: boolean + onClose: () => void +} + +export function ColumnCustomizer({ columns, onChange, open, onClose }: ColumnCustomizerProps) { + return ( + + ) +} diff --git a/frontend/src/components/DatePicker.tsx b/frontend/src/components/DatePicker.tsx new file mode 100644 index 0000000..ef4fe81 --- /dev/null +++ b/frontend/src/components/DatePicker.tsx @@ -0,0 +1,235 @@ +import { useState, useRef, useEffect } from 'react' +import { motion, AnimatePresence } from 'framer-motion' +import { Calendar, ChevronLeft, ChevronRight } from 'lucide-react' + +interface DatePickerProps { + value: string // YYYY-MM-DD + onChange: (v: string) => void + min?: string + max?: string + placeholder?: string + className?: string + buttonClassName?: string + align?: 'left' | 'right' +} + +const WEEKDAYS = ['一', '二', '三', '四', '五', '六', '日'] + +function pad(n: number) { return String(n).padStart(2, '0') } +function toDateStr(y: number, m: number, d: number) { + return `${y}-${pad(m + 1)}-${pad(d)}` +} +function todayStr() { + const date = new Date() + return toDateStr(date.getFullYear(), date.getMonth(), date.getDate()) +} +function viewDate(value: string, min?: string, max?: string) { + const source = value || max || min || todayStr() + return { + year: Number(source.slice(0, 4)), + month: Number(source.slice(5, 7)) - 1, + } +} + +export function DatePicker({ + value, + onChange, + min, + max, + placeholder = '选择日期', + className = '', + buttonClassName = '', + align = 'right', +}: DatePickerProps) { + const [open, setOpen] = useState(false) + const [showYearPicker, setShowYearPicker] = useState(false) + const ref = useRef(null) + + // 当前显示的月份 + const [viewYear, setViewYear] = useState(() => viewDate(value, min, max).year) + const [viewMonth, setViewMonth] = useState(() => viewDate(value, min, max).month) + + // 当 value 外部变化时同步 view + useEffect(() => { + const next = viewDate(value, min, max) + setViewYear(next.year) + setViewMonth(next.month) + }, [value, min, max]) + + // 点击外部关闭 + useEffect(() => { + if (!open) return + const handler = (e: MouseEvent) => { + if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false) + } + document.addEventListener('mousedown', handler) + return () => document.removeEventListener('mousedown', handler) + }, [open]) + + const prevMonth = () => { + if (viewMonth === 0) { setViewMonth(11); setViewYear(viewYear - 1) } + else setViewMonth(viewMonth - 1) + } + const nextMonth = () => { + if (viewMonth === 11) { setViewMonth(0); setViewYear(viewYear + 1) } + else setViewMonth(viewMonth + 1) + } + + // 构建日历格子: 周一为第一天 + const firstDay = new Date(viewYear, viewMonth, 1).getDay() + const offset = firstDay === 0 ? 6 : firstDay - 1 // 周一=0 + const daysInMonth = new Date(viewYear, viewMonth + 1, 0).getDate() + const prevMonthDays = new Date(viewYear, viewMonth, 0).getDate() + + const cells: { day: number; cur: boolean; dateStr: string; disabled: boolean }[] = [] + + // 上月尾部 + for (let i = offset - 1; i >= 0; i--) { + const d = prevMonthDays - i + const m = viewMonth === 0 ? 11 : viewMonth - 1 + const y = viewMonth === 0 ? viewYear - 1 : viewYear + const ds = toDateStr(y, m, d) + cells.push({ day: d, cur: false, dateStr: ds, disabled: !!min && ds < min || !!max && ds > max }) + } + // 当月 + for (let d = 1; d <= daysInMonth; d++) { + const ds = toDateStr(viewYear, viewMonth, d) + cells.push({ day: d, cur: true, dateStr: ds, disabled: !!min && ds < min || !!max && ds > max }) + } + // 下月头部 — 补齐到 6 行 × 7 = 42 + const remain = 42 - cells.length + for (let d = 1; d <= remain; d++) { + const m = viewMonth === 11 ? 0 : viewMonth + 1 + const y = viewMonth === 11 ? viewYear + 1 : viewYear + const ds = toDateStr(y, m, d) + cells.push({ day: d, cur: false, dateStr: ds, disabled: !!min && ds < min || !!max && ds > max }) + } + + const displayLabel = value || placeholder + const today = todayStr() + + return ( +
    + {/* 触发按钮 */} + + + {/* 弹出日历 */} + + {open && ( + + {/* 月份导航 */} +
    + + + +
    + + {showYearPicker ? ( + /* 年份选择网格 */ +
    + {Array.from({ length: 12 }, (_, i) => viewYear - 5 + i).map(y => { + const isSelected = y === Number(value.slice(0, 4)) + const isThisYear = y === new Date().getFullYear() + return ( + + ) + })} +
    + ) : ( + <> + {/* 星期头 */} +
    + {WEEKDAYS.map((w) => ( +
    {w}
    + ))} +
    + + {/* 日期格子 */} +
    + {cells.map((c, i) => { + const isSelected = c.dateStr === value + const isToday = c.dateStr === today + return ( + + ) + })} +
    + + )} +
    + )} +
    +
    + ) +} diff --git a/frontend/src/components/EChartsCandlestick.tsx b/frontend/src/components/EChartsCandlestick.tsx new file mode 100644 index 0000000..b322afb --- /dev/null +++ b/frontend/src/components/EChartsCandlestick.tsx @@ -0,0 +1,1085 @@ +import { useEffect, useRef, useCallback, useMemo } from 'react' +import * as echarts from 'echarts' +import type { ECharts, EChartsOption } from 'echarts' + +export interface OHLC { + date: string + open: number + high: number + low: number + close: number + volume?: number + ma5?: number | null + ma10?: number | null + ma20?: number | null + ma60?: number | null + macd_dif?: number | null + macd_dea?: number | null + macd_hist?: number | null + rsi_6?: number | null + rsi_14?: number | null + rsi_24?: number | null + kdj_k?: number | null + kdj_d?: number | null + kdj_j?: number | null + boll_upper?: number | null + boll_lower?: number | null +} + +export interface ChartMarker { + date: string + kind: 'buy' | 'sell' | 'neutral' + label?: string + /** 若为 true,标记放在蜡烛上方(如涨停连板标签)。 */ + above?: boolean + /** 自定义标签颜色,覆盖默认的 kind 对应色。 */ + color?: string +} + +export interface ChartRange { + start: string + end: string + label?: string + color?: string +} + +export interface ChartPriceLine { + value: number + label?: string + color?: string + start?: string + end?: string +} + +export interface StockInfo { + name?: string + total_shares?: number + float_shares?: number +} + +/** 子图定义 */ +export interface SubChartDef { + key: string + label: string + /** 子图固定高度 px */ + height: number + /** 构建 series 数组 */ + buildSeries: (data: OHLC[]) => any[] + /** 构建信息栏文字 (当前数据行 -> 显示内容) */ + buildInfo: (d: OHLC | null) => { label: string; color: string; value: string }[] + /** Y 轴特殊配置 */ + yAxisConfig?: Record +} + +// ===== 成交量 N 日均量 ===== +function volMaN(data: OHLC[], n: number): (number | null)[] { + const result: (number | null)[] = [] + for (let i = 0; i < data.length; i++) { + if (i < n - 1) { result.push(null); continue } + let sum = 0 + for (let j = i - n + 1; j <= i; j++) sum += data[j].volume ?? 0 + result.push(sum / n) + } + return result +} + +function fmtVol(v: number | null | undefined): string { + if (v == null) return '—' + if (v >= 1e8) return (v / 1e8).toFixed(2) + '亿' + if (v >= 1e4) return (v / 1e4).toFixed(0) + '万' + return v.toFixed(0) +} + +export const SUB_CHARTS: SubChartDef[] = [ + { + key: 'vol', + label: '成交量', + height: 84, + yAxisConfig: { min: 0 }, + buildSeries: (data) => { + const ma5Data = volMaN(data, 5) + const ma10Data = volMaN(data, 10) + return [ + { + name: '成交量', + type: 'bar', + data: data.map(d => ({ + value: d.volume ?? 0, + itemStyle: { + color: d.close >= d.open ? 'rgba(240,68,56,0.6)' : 'rgba(18,183,106,0.6)', + }, + })), + barWidth: '60%', + animation: false, + }, + { + name: 'VOL5', + type: 'line', + data: ma5Data, + smooth: true, symbol: 'none', animation: false, + lineStyle: { width: 1, color: '#FACC15' }, + itemStyle: { color: '#FACC15' }, + }, + { + name: 'VOL10', + type: 'line', + data: ma10Data, + smooth: true, symbol: 'none', animation: false, + lineStyle: { width: 1, color: '#8B5CF6' }, + itemStyle: { color: '#8B5CF6' }, + }, + ] + }, + buildInfo: (d) => { + if (!d) return [] + return [ + { label: '量', color: d.close >= d.open ? '#C74040' : '#2D9B65', value: fmtVol(d.volume) }, + ] + }, + }, + { + key: 'macd', + label: 'MACD', + height: 72, + buildSeries: (data) => [ + { + name: 'DIF', + type: 'line', + data: data.map(d => d.macd_dif != null ? Number(d.macd_dif) : '-'), + smooth: true, symbol: 'none', animation: false, + lineStyle: { width: 1, color: '#FACC15' }, + itemStyle: { color: '#FACC15' }, + }, + { + name: 'DEA', + type: 'line', + data: data.map(d => d.macd_dea != null ? Number(d.macd_dea) : '-'), + smooth: true, symbol: 'none', animation: false, + lineStyle: { width: 1, color: '#8B5CF6' }, + itemStyle: { color: '#8B5CF6' }, + }, + { + name: 'MACD', + type: 'bar', + data: data.map(d => { + const v = d.macd_hist + if (v == null) return '-' + return { + value: Number(v), + itemStyle: { color: Number(v) >= 0 ? 'rgba(240,68,56,0.6)' : 'rgba(18,183,106,0.6)' }, + } + }), + barWidth: '40%', + animation: false, + }, + ], + buildInfo: (d) => { + if (!d) return [] + return [ + { label: 'DIF', color: '#FACC15', value: d.macd_dif != null ? d.macd_dif.toFixed(3) : '—' }, + { label: 'DEA', color: '#8B5CF6', value: d.macd_dea != null ? d.macd_dea.toFixed(3) : '—' }, + { label: 'MACD', color: d.macd_hist != null && d.macd_hist >= 0 ? '#C74040' : '#2D9B65', value: d.macd_hist != null ? d.macd_hist.toFixed(3) : '—' }, + ] + }, + }, + { + key: 'rsi', + label: 'RSI', + height: 72, + yAxisConfig: { min: 0, max: 100 }, + buildSeries: (data) => [ + { + name: 'RSI6', + type: 'line', + data: data.map(d => d.rsi_6 != null ? Number(d.rsi_6) : '-'), + smooth: true, symbol: 'none', animation: false, + lineStyle: { width: 1, color: '#FACC15' }, + itemStyle: { color: '#FACC15' }, + }, + { + name: 'RSI14', + type: 'line', + data: data.map(d => d.rsi_14 != null ? Number(d.rsi_14) : '-'), + smooth: true, symbol: 'none', animation: false, + lineStyle: { width: 1, color: '#3B82F6' }, + itemStyle: { color: '#3B82F6' }, + }, + { + name: 'RSI24', + type: 'line', + data: data.map(d => d.rsi_24 != null ? Number(d.rsi_24) : '-'), + smooth: true, symbol: 'none', animation: false, + lineStyle: { width: 1, color: '#8B5CF6' }, + itemStyle: { color: '#8B5CF6' }, + }, + ], + buildInfo: (d) => { + if (!d) return [] + return [ + { label: 'RSI6', color: '#FACC15', value: d.rsi_6 != null ? d.rsi_6.toFixed(1) : '—' }, + { label: 'RSI14', color: '#3B82F6', value: d.rsi_14 != null ? d.rsi_14.toFixed(1) : '—' }, + { label: 'RSI24', color: '#8B5CF6', value: d.rsi_24 != null ? d.rsi_24.toFixed(1) : '—' }, + ] + }, + }, + { + key: 'kdj', + label: 'KDJ', + height: 72, + buildSeries: (data) => [ + { + name: 'K', + type: 'line', + data: data.map(d => d.kdj_k != null ? Number(d.kdj_k) : '-'), + smooth: true, symbol: 'none', animation: false, + lineStyle: { width: 1, color: '#FACC15' }, + itemStyle: { color: '#FACC15' }, + }, + { + name: 'D', + type: 'line', + data: data.map(d => d.kdj_d != null ? Number(d.kdj_d) : '-'), + smooth: true, symbol: 'none', animation: false, + lineStyle: { width: 1, color: '#3B82F6' }, + itemStyle: { color: '#3B82F6' }, + }, + { + name: 'J', + type: 'line', + data: data.map(d => d.kdj_j != null ? Number(d.kdj_j) : '-'), + smooth: true, symbol: 'none', animation: false, + lineStyle: { width: 1, color: '#8B5CF6' }, + itemStyle: { color: '#8B5CF6' }, + }, + ], + buildInfo: (d) => { + if (!d) return [] + return [ + { label: 'K', color: '#FACC15', value: d.kdj_k != null ? d.kdj_k.toFixed(1) : '—' }, + { label: 'D', color: '#3B82F6', value: d.kdj_d != null ? d.kdj_d.toFixed(1) : '—' }, + { label: 'J', color: '#8B5CF6', value: d.kdj_j != null ? d.kdj_j.toFixed(1) : '—' }, + ] + }, + }, +] + +/** 向后兼容的 INDICATORS 导出 (不含 vol) */ +export const INDICATORS = SUB_CHARTS.filter(s => s.key !== 'vol') + +/** 主图叠加指标 (画在 K 线上方, 不占副图空间) */ +export const OVERLAY_INDICATORS: { key: string; label: string }[] = [ + { key: 'boll', label: 'BOLL' }, +] + +interface Props { + data: OHLC[] + markers?: ChartMarker[] + ranges?: ChartRange[] + priceLines?: ChartPriceLine[] + height?: number + showMA?: boolean + showInfoBar?: boolean + showMarkers?: boolean + onToggleMarkers?: () => void + stockInfo?: StockInfo + symbol?: string + linkedPrice?: number | null + onDateClick?: (date: string) => void + /** 默认可见蜡烛根数, 默认 60 */ + visibleBars?: number + /** 已激活的子图 key 列表 (含 vol, 按点击顺序) */ + activeIndicators?: string[] +} + +const THEME = { + bull: '#C74040', + bear: '#2D9B65', + bullAlpha: 'rgba(240,68,56,0.7)', + bearAlpha: 'rgba(18,183,106,0.7)', + ma5: '#A1A1AA', + ma10: '#3B82F6', + ma20: '#F97316', + ma60: '#8B5CF6', + text: '#A1A1AA', + grid: 'rgba(255,255,255,0.04)', + border: '#27272A', + bg: 'transparent', +} + +/** 可见蜡烛超过此数量时,涨停/炸板标签切换为小圆点。 */ +const COMPACT_THRESHOLD = 60 + +/** 子图上方信息栏高度 (px) */ +const INFO_BAR_H = 16 +/** 子图之间的间距 (px) */ +const SUB_GAP_PX = 4 + +function buildSubInfoGraphics( + data: OHLC[], + infoIdx: number, + activeIndicators: string[], + subStartTop: number, +): any[] { + const d = infoIdx >= 0 && infoIdx < data.length ? data[infoIdx] : null + const graphics: any[] = [] + let curTop = subStartTop + + activeIndicators.forEach((key) => { + const def = SUB_CHARTS.find(s => s.key === key) + if (!def) return + + const items = def.buildInfo(d) + if (def.key === 'vol' && d) { + const calcVolMa = (n: number) => { + if (infoIdx < n - 1) return null + let sum = 0 + for (let j = infoIdx - n + 1; j <= infoIdx; j++) sum += data[j].volume ?? 0 + return sum / n + } + const vol5 = calcVolMa(5) + const vol10 = calcVolMa(10) + items.push({ label: 'VOL5', color: '#FACC15', value: fmtVol(vol5) }) + items.push({ label: 'VOL10', color: '#8B5CF6', value: fmtVol(vol10) }) + } + + // 每个元素加固定 id,确保 ECharts 增量更新时能正确匹配 + graphics.push({ + id: `sub-sep-${key}`, + type: 'line', + shape: { x1: 0, y1: curTop, x2: 2000, y2: curTop }, + style: { stroke: 'rgba(255,255,255,0.08)', lineWidth: 1 }, + silent: true, z: 0, + }) + graphics.push({ + id: `sub-label-${key}`, + type: 'text', + style: { + text: def.label, + x: 4, y: curTop + 4, + fill: '#8E8E96', + fontSize: 10, fontFamily: 'JetBrains Mono, monospace', + fontWeight: 'bold', + }, + silent: true, z: 10, + }) + + const richTextParts: string[] = [] + const rich: Record = {} + items.forEach((item, idx) => { + const styleKey = `s${idx}` + richTextParts.push(`{${styleKey}|${item.label}:${item.value}}`) + rich[styleKey] = { + fill: item.color, + fontSize: 10, + fontFamily: 'JetBrains Mono, monospace', + } + }) + graphics.push({ + id: `sub-val-${key}`, + type: 'text', + right: 24, + style: { + text: richTextParts.join(`{gap| }`), + y: curTop + 3, + rich: { + gap: { fill: 'transparent', fontSize: 10 }, + ...rich, + }, + fontSize: 10, + fontFamily: 'JetBrains Mono, monospace', + textAlign: 'right', + textVerticalAlign: 'top', + }, + silent: true, z: 10, + }) + + curTop += INFO_BAR_H + def.height + SUB_GAP_PX + }) + + return graphics +} + +function buildOption( + data: OHLC[], + dates: string[], + dateIndexMap: Map, + markers: ChartMarker[] | undefined, + ranges: ChartRange[] | undefined, + priceLines: ChartPriceLine[] | undefined, + showMA: boolean, + compact: boolean, + activeIndicators: string[], + containerHeight: number, + infoIdx: number, + linkedPrice: number | null | undefined, +): EChartsOption { + const candleData = data.map(d => [d.open, d.close, d.low, d.high]) + + const hasMA = showMA && data.some(d => d.ma5 != null || d.ma10 != null || d.ma20 != null || d.ma60 != null) + + const markPointData: any[] = [] + if (markers && markers.length > 0) { + for (const m of markers) { + const idx = dateIndexMap.get(m.date) + if (idx == null) continue + const d = data[idx] + const isBuy = m.kind === 'buy' + const isSell = m.kind === 'sell' + + if (m.above) { + const dotColor = m.color ?? (isBuy ? '#FACC15' : THEME.text) + if (compact) { + markPointData.push({ + name: m.date, coord: [m.date, d.high], + symbol: 'circle', symbolSize: 4, symbolOffset: [0, -10], + itemStyle: { color: dotColor, cursor: 'pointer' }, + label: { show: false }, z: 100, zlevel: 10, + }) + } else { + markPointData.push({ + name: m.date, coord: [m.date, d.high], + symbol: 'circle', symbolSize: 12, symbolOffset: [0, -2], + itemStyle: { color: 'transparent' }, + label: { + show: true, formatter: m.label ?? '', position: 'top', distance: 0, + color: dotColor, fontSize: 10, fontWeight: 'normal', + fontFamily: 'JetBrains Mono, monospace', + }, + z: 100, zlevel: 10, + }) + } + } else { + markPointData.push({ + name: m.label ?? '', + coord: [m.date, isBuy ? d.low : d.high], + symbol: 'arrow', symbolSize: 12, + symbolRotate: isBuy ? 0 : 180, + symbolOffset: isBuy ? [0, '60%'] : [0, '-60%'], + itemStyle: { color: isBuy ? THEME.bull : isSell ? THEME.bear : THEME.text }, + label: { + show: !!m.label, formatter: m.label ?? '', + position: isBuy ? 'bottom' : 'top', distance: 8, + color: THEME.text, fontSize: 10, + fontFamily: 'JetBrains Mono, monospace', + }, + }) + } + } + } + + // ====== 布局计算 ====== + const left = 60 + const right = 20 + const topPad = 8 + const candleBottomPad = 22 + + let subTotalH = 0 + const activeSubDefs: SubChartDef[] = [] + activeIndicators.forEach(key => { + const def = SUB_CHARTS.find(s => s.key === key) + if (!def) return + activeSubDefs.push(def) + subTotalH += INFO_BAR_H + def.height + }) + if (activeSubDefs.length > 0) subTotalH += activeSubDefs.length * SUB_GAP_PX + + const candleAvail = Math.max(containerHeight - topPad - candleBottomPad - subTotalH, 100) + + const grids: any[] = [] + const xAxes: any[] = [] + const yAxes: any[] = [] + const series: any[] = [] + const xAxisIndices: number[] = [] + + // ===== grid 0: K线主图 ===== + grids.push({ left, right, top: topPad, height: candleAvail }) + xAxes.push({ + type: 'category', data: dates, boundaryGap: true, + axisLine: { lineStyle: { color: THEME.border } }, + axisLabel: { color: THEME.text, fontSize: 10, fontFamily: 'JetBrains Mono, monospace' }, + axisTick: { show: false }, + splitLine: { show: false }, + }) + yAxes.push({ + scale: true, + // 上下各留 3% 边距: 防止最高/最低点的蜡烛贴边, 涨停/炸板标签被遮挡 + boundaryGap: [0.03, 0.03], + splitArea: { show: false }, + axisLine: { show: false }, axisTick: { show: false }, + splitLine: { lineStyle: { color: THEME.grid } }, + axisLabel: { color: THEME.text, fontSize: 10, fontFamily: 'JetBrains Mono, monospace' }, + }) + xAxisIndices.push(0) + + const markAreaData = (ranges ?? []) + .filter(r => dateIndexMap.has(r.start) && dateIndexMap.has(r.end)) + .map(r => ([ + { + name: r.label ?? '', + xAxis: r.start, + itemStyle: { color: r.color ?? 'rgba(59,130,246,0.08)' }, + label: { + show: !!r.label, + position: 'insideTop', + distance: 8, + color: '#DBEAFE', + backgroundColor: 'rgba(15,23,42,0.72)', + borderColor: 'rgba(59,130,246,0.35)', + borderWidth: 1, + borderRadius: 4, + padding: [2, 6], + fontSize: 10, + fontFamily: 'JetBrains Mono, monospace', + }, + }, + { xAxis: r.end }, + ])) + + const markLineData: any[] = (priceLines ?? []) + .filter(line => Number.isFinite(line.value)) + .map(line => { + const lineStyle = { + color: line.color ?? THEME.text, + type: 'dashed' as const, + width: 1, + opacity: 0.92, + } + const label = { + show: !!line.label, + formatter: line.label ?? '', + position: 'insideEndTop' as const, + color: line.color ?? THEME.text, + backgroundColor: 'rgba(15,23,42,0.72)', + borderRadius: 4, + padding: [2, 6], + fontSize: 10, + fontFamily: 'JetBrains Mono, monospace', + } + if (line.start && line.end && dateIndexMap.has(line.start) && dateIndexMap.has(line.end)) { + return [ + { xAxis: line.start, yAxis: line.value }, + { xAxis: line.end, yAxis: line.value, lineStyle, label, symbol: 'none' }, + ] + } + return { yAxis: line.value, lineStyle, label, symbol: 'none' } + }) + + if (linkedPrice != null) { + markLineData.push({ + yAxis: linkedPrice, + lineStyle: { color: '#3B82F6', type: 'dashed', width: 1, opacity: 0.7 }, + label: { + show: true, + formatter: linkedPrice.toFixed(2), + position: 'insideEndTop', + color: '#3B82F6', + fontSize: 10, + fontFamily: 'JetBrains Mono, monospace', + backgroundColor: 'rgba(24,24,27,0.85)', + borderColor: '#3B82F6', + borderWidth: 1, + padding: [1, 4], + borderRadius: 2, + }, + symbol: 'none', + }) + } + + series.push({ + name: 'K', type: 'candlestick', data: candleData, + animation: false, + itemStyle: { + color: THEME.bull, color0: THEME.bear, + borderColor: THEME.bull, borderColor0: THEME.bear, + cursor: 'pointer', + }, + markPoint: markPointData.length > 0 ? { data: markPointData, animation: false } : undefined, + markArea: markAreaData.length > 0 ? { silent: true, data: markAreaData } : undefined, + markLine: markLineData.length > 0 ? { silent: true, symbol: 'none', data: markLineData, animation: false } : undefined, + }) + + if (hasMA) { + const maLine = (key: keyof OHLC, color: string, name: string) => ({ + name, type: 'line', + data: data.map(d => (d[key] != null ? Number(d[key]) : '-')), + smooth: true, symbol: 'none', animation: false, + silent: true, + lineStyle: { width: 1, color }, itemStyle: { color }, + }) + series.push(maLine('ma5', THEME.ma5, 'MA5')) + series.push(maLine('ma10', THEME.ma10, 'MA10')) + series.push(maLine('ma20', THEME.ma20, 'MA20')) + series.push(maLine('ma60', THEME.ma60, 'MA60')) + } + + // BOLL 布林带 — 需在 activeIndicators 中激活 + const showBOLL = activeIndicators.includes('boll') && data.some(d => d.boll_upper != null || d.boll_lower != null) + if (showBOLL) { + const bollLine = (key: keyof OHLC, color: string, name: string) => ({ + name, type: 'line', + data: data.map(d => (d[key] != null ? Number(d[key]) : '-')), + smooth: true, symbol: 'none', animation: false, + silent: true, + lineStyle: { width: 1, color, type: 'dashed' as const }, itemStyle: { color }, + }) + series.push(bollLine('boll_upper', '#E879F9', 'BOLL上')) + series.push(bollLine('boll_lower', '#E879F9', 'BOLL下')) + } + + // ===== 子图区域 ===== + let curTop = topPad + candleAvail + candleBottomPad + + activeSubDefs.forEach((def, i) => { + const gridIdx = i + 1 + const xAxisIdx = i + 1 + const yAxisIdx = i + 1 + + const chartTop = curTop + INFO_BAR_H + grids.push({ + left, right, + top: chartTop, + height: def.height, + show: true, + borderColor: 'rgba(255,255,255,0.06)', + borderWidth: 1, + }) + + xAxes.push({ + type: 'category', gridIndex: gridIdx, data: dates, boundaryGap: true, + axisLine: { show: false }, axisLabel: { show: false }, + axisTick: { show: false }, splitLine: { show: false }, + axisPointer: { label: { show: false } }, + }) + + const isFixedRange = !!def.yAxisConfig + yAxes.push({ + scale: !isFixedRange, + ...(isFixedRange ? def.yAxisConfig : {}), + gridIndex: gridIdx, + splitNumber: 2, + axisLine: { show: false }, axisTick: { show: false }, + splitLine: { lineStyle: { color: THEME.grid } }, + axisLabel: { + show: true, color: THEME.text, fontSize: 9, + fontFamily: 'JetBrains Mono, monospace', + }, + }) + + xAxisIndices.push(xAxisIdx) + + const subSeries = def.buildSeries(data) + subSeries.forEach((s: any) => { + series.push({ ...s, xAxisIndex: xAxisIdx, yAxisIndex: yAxisIdx }) + }) + + curTop += INFO_BAR_H + def.height + SUB_GAP_PX + }) + + // 子图信息栏 graphic + const subStartTop = topPad + candleAvail + candleBottomPad + const infoGraphics = buildSubInfoGraphics(data, infoIdx, activeIndicators, subStartTop) + + return { + animation: false, + backgroundColor: THEME.bg, + tooltip: { + trigger: 'axis', + axisPointer: { type: 'cross', crossStyle: { color: '#555' } }, + backgroundColor: 'transparent', + borderWidth: 0, + textStyle: { fontSize: 0 }, + formatter: () => '', + }, + axisPointer: { + link: [{ xAxisIndex: 'all' }], + label: { + backgroundColor: '#333', + fontFamily: 'JetBrains Mono, monospace', + fontSize: 10, + }, + }, + graphic: infoGraphics.length > 0 ? infoGraphics : undefined, + grid: grids, + xAxis: xAxes, + yAxis: yAxes, + dataZoom: [ + { + type: 'inside', + xAxisIndex: xAxisIndices, + start: 0, + end: 100, + moveOnMouseMove: true, + zoomOnMouseWheel: true, + }, + ], + series, + } +} + + +export function EChartsCandlestick({ + data, + markers, + ranges, + priceLines, + height = 480, + showMA = true, + showInfoBar = true, + showMarkers: showMarkersProp = true, + onToggleMarkers: _onToggleMarkers, + stockInfo, + symbol: _symbol, + linkedPrice, + onDateClick, + visibleBars = 60, + activeIndicators = [], +}: Props) { + const containerRef = useRef(null) + const chartRef = useRef(null) + const dataRef = useRef(data) + dataRef.current = data + const onDateClickRef = useRef(onDateClick) + onDateClickRef.current = onDateClick + + // --- 全部用 ref,避免高频交互触发 React 重渲染 --- + const infoIdxRef = useRef(data.length - 1) + const compactRef = useRef(false) + const userZoomRef = useRef<{ start: number; end: number } | null>(null) + + // 需要在闭包中访问最新值的变量 — 先声明占位,后面赋值 + const activeIndicatorsRef = useRef(activeIndicators) + activeIndicatorsRef.current = activeIndicators + const chartHeightRef = useRef(300) + const subTotalHRef = useRef(0) + const getInfoBarHTMLRef = useRef<() => string>(() => '') + + // 强制刷新信息栏 DOM 的回调 + const infoBarRef = useRef(null) + const triggerInfoBarUpdate = useRef(() => { + const idx = infoIdxRef.current + const curData = dataRef.current + const d = idx >= 0 && idx < curData.length ? curData[idx] : null + if (!d) return + const chart = chartRef.current + if (!chart) return + const subStartTop = chartHeightRef.current - subTotalHRef.current + const infoGraphics = buildSubInfoGraphics(curData, idx, activeIndicatorsRef.current, subStartTop) + if (infoGraphics.length > 0) { + chart.setOption({ graphic: infoGraphics }, { lazyUpdate: true }) + } + }).current + + // 计算子图总高度 + const activeSubDefs = activeIndicators + .map(key => SUB_CHARTS.find(s => s.key === key)) + .filter((d): d is SubChartDef => !!d) + + let subTotalH = 0 + activeSubDefs.forEach(def => { subTotalH += INFO_BAR_H + def.height }) + if (activeSubDefs.length > 0) subTotalH += activeSubDefs.length * SUB_GAP_PX + + const mainInfoBarH = showInfoBar ? 40 : 0 + const minCandleH = 120 + + const chartHeight = Math.max(height - mainInfoBarH, 8 + minCandleH + 14 + subTotalH) + chartHeightRef.current = chartHeight + subTotalHRef.current = subTotalH + + // 预计算 date→index Map (O(1) 查找) + const dates = useMemo(() => data.map(d => d.date), [data]) + const dateIndexMap = useMemo(() => { + const m = new Map() + dates.forEach((d, i) => m.set(d, i)) + return m + }, [dates]) + + // 计算 dataZoom 初始范围 + const initialZoom = useMemo(() => ({ + start: Math.max(0, 100 - (visibleBars / Math.max(data.length, 1)) * 100), + end: 100, + }), [visibleBars, data.length]) + + // ===== 信息栏 HTML 内容 (基于 infoIdxRef.current) ===== + const getInfoBarHTML = useCallback(() => { + let idx = infoIdxRef.current + let d = idx >= 0 && idx < data.length ? data[idx] : null + // fallback: 如果当前 idx 无数据,取最后一根 K 线 + if (!d && data.length > 0) { + idx = data.length - 1 + d = data[idx] + } + if (!d) return '' + const prev = idx > 0 ? data[idx - 1] : null + const chg = prev ? d.close - prev.close : 0 + const isUp = chg >= 0 + const clr = isUp ? THEME.bull : THEME.bear + const floatShares = stockInfo?.float_shares + const turnoverRate = floatShares && d.volume ? (d.volume * 100 / floatShares * 100) : null + + let html = `
    ` + html += `${d.date}` + html += `` + html += `${d.open.toFixed(2)}` + html += `` + html += `${d.high.toFixed(2)}` + html += `` + html += `${d.low.toFixed(2)}` + html += `` + html += `${d.close.toFixed(2)}` + if (turnoverRate != null) { + html += `换手` + html += `${turnoverRate.toFixed(2)}%` + } + html += `
    ` + + // 第二行: MA + BOLL + if (showMA) { + html += `
    ` + if (d.ma5 != null) html += `MA5:${Number(d.ma5).toFixed(2)}` + if (d.ma10 != null) html += `MA10:${Number(d.ma10).toFixed(2)}` + if (d.ma20 != null) html += `MA20:${Number(d.ma20).toFixed(2)}` + if (d.ma60 != null) html += `MA60:${Number(d.ma60).toFixed(2)}` + if (d.boll_upper != null && activeIndicators.includes('boll')) { + html += `BOLL:${Number(d.boll_upper).toFixed(2)}/${Number(d.ma20).toFixed(2)}/${Number(d.boll_lower).toFixed(2)}` + } + html += `
    ` + } + + return html + }, [data, stockInfo, showMA, activeIndicators]) + getInfoBarHTMLRef.current = getInfoBarHTML + + // data 变化时重置 infoIdx + useEffect(() => { + infoIdxRef.current = data.length - 1 + compactRef.current = false + userZoomRef.current = null + }, [data.length]) + + // ===== 初始化 chart (只在 chartHeight 变化时重建) ===== + useEffect(() => { + const el = containerRef.current + if (!el) return + + const chart = echarts.init(el, undefined, { renderer: 'canvas' }) + chartRef.current = chart + + // 鼠标移动 → 只更新 ref + DOM,不触发 React re-render + // 设计原则: 找不到有效数据时保持上次显示,永远不清空信息栏 + chart.on('updateAxisPointer', (event: any) => { + const axesInfo = event.axesInfo + if (!axesInfo) return // 鼠标移出图表区域,保持当前显示 + for (const info of Object.values(axesInfo)) { + const val = (info as any)?.value + if (val == null) continue + const d = dataRef.current + const idx = typeof val === 'number' ? val : d.findIndex(x => x.date === val) + if (idx >= 0 && idx < d.length) { + if (infoIdxRef.current === idx) return + infoIdxRef.current = idx + + // 直接更新信息栏 DOM (通过 ref 读取最新的生成函数) + const infoEl = infoBarRef.current + if (infoEl) { + const html = getInfoBarHTMLRef.current() + if (html) infoEl.innerHTML = html // 只在有内容时更新 + } + + // 更新子图 graphic + triggerInfoBarUpdate() + return + } + } + // 没有找到有效数据 — 不做任何操作,保持上次显示 + }) + + chart.on('click', (params: any) => { + if (params.componentType === 'markPoint' && params.name) { + onDateClickRef.current?.(params.name) + return + } + if (params.seriesName !== 'K' || params.dataIndex == null) return + const d = dataRef.current + const idx = params.dataIndex + if (idx >= 0 && idx < d.length) { + onDateClickRef.current?.(d[idx].date) + } + }) + + // dataZoom → 只更新 ref,不触发 React re-render + // compact 变化时需要增量更新 markPoint + chart.on('dataZoom', () => { + const opt = chart.getOption() as any + const zoom = opt?.dataZoom?.[0] + if (!zoom) return + userZoomRef.current = { start: zoom.start, end: zoom.end } + + const d = dataRef.current + const total = d.length + const visibleCount = Math.round(total * (zoom.end - zoom.start) / 100) + const newCompact = visibleCount > COMPACT_THRESHOLD + if (newCompact !== compactRef.current) { + compactRef.current = newCompact + // compact 变了需要更新 markPoint,但只更新 markPoint series + // 通过 dispatch 自定义事件来增量更新 + updateMarkPoints() + } + }) + + const ro = new ResizeObserver(() => { chart.resize() }) + ro.observe(el) + + return () => { + chart.off('updateAxisPointer') + chart.off('click') + chart.off('dataZoom') + ro.disconnect() + chart.dispose() + chartRef.current = null + } + }, [chartHeight]) // eslint-disable-line react-hooks/exhaustive-deps + + // 增量更新 markPoint (compact 切换时) + function updateMarkPoints() { + const chart = chartRef.current + if (!chart) return + const mkrs = showMarkersProp ? markers : undefined + if (!mkrs || mkrs.length === 0) return + const compact = compactRef.current + const markPointData: any[] = [] + for (const m of mkrs) { + const idx = dateIndexMap.get(m.date) + if (idx == null) continue + const d = data[idx] + const isBuy = m.kind === 'buy' + const isSell = m.kind === 'sell' + if (m.above) { + const dotColor = m.color ?? (isBuy ? '#FACC15' : THEME.text) + if (compact) { + markPointData.push({ + name: m.date, coord: [m.date, d.high], + symbol: 'circle', symbolSize: 4, symbolOffset: [0, -10], + itemStyle: { color: dotColor, cursor: 'pointer' }, + label: { show: false }, z: 100, zlevel: 10, + }) + } else { + markPointData.push({ + name: m.date, coord: [m.date, d.high], + symbol: 'circle', symbolSize: 12, symbolOffset: [0, -2], + itemStyle: { color: 'transparent' }, + label: { + show: true, formatter: m.label ?? '', position: 'top', distance: 0, + color: dotColor, fontSize: 10, fontWeight: 'normal', + fontFamily: 'JetBrains Mono, monospace', + }, + z: 100, zlevel: 10, + }) + } + } else { + markPointData.push({ + name: m.label ?? '', + coord: [m.date, isBuy ? d.low : d.high], + symbol: 'arrow', symbolSize: 12, + symbolRotate: isBuy ? 0 : 180, + symbolOffset: isBuy ? [0, '60%'] : [0, '-60%'], + itemStyle: { color: isBuy ? THEME.bull : isSell ? THEME.bear : THEME.text }, + label: { + show: !!m.label, formatter: m.label ?? '', + position: isBuy ? 'bottom' : 'top', distance: 8, + color: THEME.text, fontSize: 10, + fontFamily: 'JetBrains Mono, monospace', + }, + }) + } + } + chart.setOption({ + series: [{ + name: 'K', + markPoint: markPointData.length > 0 ? { data: markPointData, animation: false } : undefined, + }] + }) + } + + // ===== 核心: 仅在数据/配置变更时全量 setOption ===== + useEffect(() => { + const chart = chartRef.current + if (!chart) return + + const option = buildOption( + data, dates, dateIndexMap, + showMarkersProp ? markers : undefined, + ranges, + priceLines, + showMA, compactRef.current, + activeIndicators, chartHeight, + infoIdxRef.current, + linkedPrice, + ) + + chart.setOption(option, true) + + // 恢复用户缩放位置 + const zoom = userZoomRef.current + if (zoom) { + chart.dispatchAction({ type: 'dataZoom', start: zoom.start, end: zoom.end }) + } else { + chart.dispatchAction({ type: 'dataZoom', start: initialZoom.start, end: initialZoom.end }) + } + + // 初始信息栏 + const infoEl = infoBarRef.current + if (infoEl) { + infoEl.innerHTML = getInfoBarHTML() + } + }, [data, markers, ranges, priceLines, linkedPrice, showMA, showMarkersProp, activeIndicators, chartHeight, dates, dateIndexMap, initialZoom, getInfoBarHTML]) + + // 渲染信息栏容器 (内容由 JS 直接写入) + const initialHTML = useMemo(() => { + const idx = data.length - 1 + const d = idx >= 0 && idx < data.length ? data[idx] : null + if (!d) return '' + const floatShares = stockInfo?.float_shares + const turnoverRate = floatShares && d.volume ? (d.volume * 100 / floatShares * 100) : null + let html = `
    ` + html += `${d.date}` + html += `` + html += `${d.open.toFixed(2)}` + html += `` + html += `${d.high.toFixed(2)}` + html += `` + html += `${d.low.toFixed(2)}` + html += `` + html += `${d.close.toFixed(2)}` + if (turnoverRate != null) { + html += `换手` + html += `${turnoverRate.toFixed(2)}%` + } + html += `
    ` + if (showMA) { + html += `
    ` + if (d.ma5 != null) html += `MA5:${Number(d.ma5).toFixed(2)}` + if (d.ma10 != null) html += `MA10:${Number(d.ma10).toFixed(2)}` + if (d.ma20 != null) html += `MA20:${Number(d.ma20).toFixed(2)}` + if (d.ma60 != null) html += `MA60:${Number(d.ma60).toFixed(2)}` + if (d.boll_upper != null && activeIndicators.includes('boll')) { + html += `BOLL:${Number(d.boll_upper).toFixed(2)}/${Number(d.ma20).toFixed(2)}/${Number(d.boll_lower).toFixed(2)}` + } + html += `
    ` + } + return html + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + + return ( +
    + {/* 主图信息栏 — 内容由 JS 直接操作 innerHTML */} + {showInfoBar && ( +
    + )} + + {/* ECharts canvas */} +
    +
    + ) +} diff --git a/frontend/src/components/EChartsIntraday.tsx b/frontend/src/components/EChartsIntraday.tsx new file mode 100644 index 0000000..65bb6ca --- /dev/null +++ b/frontend/src/components/EChartsIntraday.tsx @@ -0,0 +1,592 @@ +import { useEffect, useMemo, useRef, useState } from 'react' +import * as echarts from 'echarts' +import type { ECharts, EChartsOption } from 'echarts' +import type { MinuteKlineRow } from '@/lib/api' + +type YMode = 'adaptive' | 'limit' + +const THEME = { + line: '#3B82F6', + areaFill: 'rgba(59,130,246,0.40)', + avgLine: '#F59E0B', + refLine: 'rgba(255,255,255,0.25)', + volUp: 'rgba(240,68,56,0.6)', + volDown: 'rgba(18,183,106,0.6)', + text: '#A1A1AA', + grid: 'rgba(255,255,255,0.04)', + border: '#27272A', +} + +interface Props { + data: MinuteKlineRow[] + height?: number + prevClose?: number + date?: string + symbol?: string + onPriceHover?: (price: number | null) => void + showLimitLines?: boolean + showAvgLine?: boolean +} + +function fmtTime(dt: string): string { + const match = dt.match(/(\d{2}):(\d{2})/) + if (!match) return dt.slice(11, 16) + const h = (parseInt(match[1]) + 8) % 24 + return `${String(h).padStart(2, '0')}:${match[2]}` +} + +function computeAvgPrice(data: MinuteKlineRow[]): number[] { + // 分时均线 = 累计成交额 / 累计成交量(手→股) + const result: number[] = [] + let sumAmt = 0 + let sumVol = 0 + for (const d of data) { + sumAmt += d.amount + sumVol += d.volume * 100 + result.push(sumVol > 0 ? sumAmt / sumVol : d.close) + } + return result +} + +function fmtAmt(v: number): string { + if (v >= 1_000_000_000) return `${(v / 1_000_000_000).toFixed(2)}亿` + if (v >= 10_000) return `${(v / 10_000).toFixed(0)}万` + return v.toFixed(0) +} + +function isValidPrice(v: number | null | undefined): v is number { + return typeof v === 'number' && Number.isFinite(v) && v > 0 +} + +/** 生成全天分时时间刻度 9:30 ~ 11:30, 13:00 ~ 15:00, 每分钟一个点 (共242个) */ +function generateFullDayTimes(): string[] { + const times: string[] = [] + // 上午 9:30 ~ 11:30 (121 分钟) + for (let h = 9; h <= 11; h++) { + const startM = h === 9 ? 30 : 0 + const endM = h === 11 ? 30 : 59 + for (let m = startM; m <= endM; m++) { + times.push(`${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`) + } + } + // 下午 13:00 ~ 15:00 (121 分钟) + for (let h = 13; h <= 15; h++) { + const endM = h === 15 ? 0 : 59 + for (let m = 0; m <= endM; m++) { + times.push(`${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`) + } + } + return times +} + +const FULL_DAY_TIMES = generateFullDayTimes() + +/** 根据 symbol 判断涨跌停幅度 (创业板/科创板 ±20%, 北交所 ±30%, 其余 ±10%) */ +function getLimitPct(symbol?: string): number { + if (!symbol) return 0.10 + if (symbol.endsWith('.BJ')) return 0.30 // 北交所 + if (symbol.startsWith('300') || symbol.startsWith('301')) return 0.20 // 创业板 + if (symbol.startsWith('688') || symbol.startsWith('689')) return 0.20 // 科创板 + return 0.10 +} + +/** 计算实际涨跌停价 (四舍五入到2位小数) 和实际涨跌停幅度 */ +function getLimitPrices(prevClose: number, symbol?: string): { + limitUp: number // 涨停价 (四舍五入) + limitDown: number // 跌停价 (四舍五入) + upPct: number // 实际涨停幅度 (如 9.97) + downPct: number // 实际跌停幅度 (如 -9.97) +} { + const pct = getLimitPct(symbol) + const rawUp = prevClose * (1 + pct) + const rawDown = prevClose * (1 - pct) + // A股涨跌停价四舍五入到分 (2位小数) + const limitUp = Math.round(rawUp * 100) / 100 + const limitDown = Math.round(rawDown * 100) / 100 + const upPct = (limitUp - prevClose) / prevClose * 100 + const downPct = (limitDown - prevClose) / prevClose * 100 + return { limitUp, limitDown, upPct, downPct } +} + +function buildOption(data: MinuteKlineRow[], prevClose: number | undefined, avgPrices: number[], lineColor: string, areaColor: string, yMode: YMode, symbol?: string, showLimitLines = true, showAvgLine = true): EChartsOption { + // 将数据映射到全天时间轴上的正确位置 + const timeIndexMap = new Map(FULL_DAY_TIMES.map((t, i) => [t, i])) + const closes = new Array(FULL_DAY_TIMES.length).fill(null) as (number | null)[] + const highs = new Array(FULL_DAY_TIMES.length).fill(null) as (number | null)[] + const lows = new Array(FULL_DAY_TIMES.length).fill(null) as (number | null)[] + const avgData = new Array(FULL_DAY_TIMES.length).fill(null) as (number | null)[] + const volumes = new Array(FULL_DAY_TIMES.length).fill(null) as (any | null)[] + + const volNeutral = 'rgba(161,161,170,0.5)' + for (let i = 0; i < data.length; i++) { + const timeKey = fmtTime(data[i].datetime) + const idx = timeIndexMap.get(timeKey) + if (idx !== undefined) { + closes[idx] = data[i].close + highs[idx] = data[i].high + lows[idx] = data[i].low + avgData[idx] = avgPrices[i] + volumes[idx] = { + value: data[i].volume, + itemStyle: { + color: data[i].close > data[i].open ? THEME.volUp : data[i].close < data[i].open ? THEME.volDown : volNeutral, + }, + } + } + } + + const areaStyle: any = { + color: { + type: 'linear', + x: 0, y: 0, x2: 0, y2: 1, + colorStops: [ + { offset: 0, color: areaColor }, + { offset: 1, color: 'rgba(0,0,0,0)' }, + ], + }, + } + + const markLineData: any[] = [] + if (prevClose != null) { + markLineData.push({ + yAxis: prevClose, + lineStyle: { color: THEME.refLine, type: 'dashed', width: 1 }, + label: { show: false }, + symbol: 'none', + }) + } + + let yMin: number | undefined + let yMax: number | undefined + let maxDiff = 0 + if (isValidPrice(prevClose) && data.length > 0) { + const priceArrays = showAvgLine ? [closes, highs, lows, avgData] : [closes, highs, lows] + for (const arr of priceArrays) { + for (const v of arr) { + if (!isValidPrice(v)) continue + const diff = Math.abs(v - prevClose) + if (diff > maxDiff) maxDiff = diff + } + } + + if (showLimitLines && yMode === 'limit') { + const { limitUp, limitDown } = getLimitPrices(prevClose, symbol) + const limitDiffUp = limitUp - prevClose + const limitDiffDown = prevClose - limitDown + const limitDiff = Math.max(limitDiffUp, limitDiffDown) + // 涨跌停模式: Y 轴按实际涨跌停价 + maxDiff = limitDiff + yMin = prevClose - maxDiff + yMax = prevClose + maxDiff + // 加 markLine 标注涨停价和跌停价 (仅虚线, 不显示文字) + markLineData.push( + { + yAxis: limitUp, + lineStyle: { color: 'rgba(199,64,64,0.4)', type: 'dashed', width: 1 }, + label: { show: false }, + symbol: 'none', + }, + { + yAxis: limitDown, + lineStyle: { color: 'rgba(45,155,101,0.4)', type: 'dashed', width: 1 }, + label: { show: false }, + symbol: 'none', + }, + ) + } else { + // 自适应模式: Y 轴按实际涨跌幅对称, 但不超出实际涨跌停范围 + if (showLimitLines) { + const { limitUp, limitDown } = getLimitPrices(prevClose, symbol) + const limitDiff = Math.max(limitUp - prevClose, prevClose - limitDown) + maxDiff = Math.min(maxDiff, limitDiff) + } + if (!showLimitLines && maxDiff > 0) { + maxDiff *= 1.1 + } + // 至少保证一个可视范围 (防止数据平时 maxDiff=0)。指数不使用涨跌停范围,最小范围要更紧,否则低波动指数会被压成横线。 + const minDiff = showLimitLines ? prevClose * 0.01 : prevClose * 0.001 + if (maxDiff < minDiff) maxDiff = minDiff + yMin = prevClose - maxDiff + yMax = prevClose + maxDiff + } + } + + // x 轴标签: 9:30, 10:30, 11:30/13:00, 14:00, 15:00 + // 11:30(idx 120) 和 13:00(idx 121) 相邻会重叠, 合并为一个标签 + const xAxisLabelMap: Record = { + 0: '9:30', + 60: '10:30', + 120: '11:30/13:00', + 181: '14:00', + 241: '15:00', + } + const xAxisLabelFormatter = (_value: string, idx: number) => { + return xAxisLabelMap[idx] ?? '' + } + + return { + animation: false, + backgroundColor: 'transparent', + tooltip: { + trigger: 'axis', + backgroundColor: 'transparent', + borderWidth: 0, + textStyle: { fontSize: 0 }, + formatter: () => '', + axisPointer: { + type: 'cross', + label: { + show: true, + backgroundColor: 'rgba(39,39,42,0.9)', + borderColor: 'rgba(255,255,255,0.1)', + borderWidth: 1, + padding: [2, 5], + color: '#A1A1AA', + fontSize: 10, + fontFamily: 'JetBrains Mono, monospace', + }, + crossStyle: { color: 'rgba(255,255,255,0.2)', type: 'dashed', width: 1 }, + lineStyle: { color: 'rgba(255,255,255,0.2)', type: 'dashed', width: 1 }, + }, + }, + axisPointer: { + link: [{ xAxisIndex: 'all' }], + }, + grid: [ + { left: 60, right: 55, top: 24, bottom: '28%' }, + { left: 60, right: 55, top: '74%', bottom: 20 }, + ], + xAxis: [ + { + type: 'category', + data: FULL_DAY_TIMES, + boundaryGap: false, + axisPointer: { + show: true, + lineStyle: { color: 'rgba(255,255,255,0.2)', type: 'dashed', width: 1 }, + label: { + show: true, + backgroundColor: 'rgba(39,39,42,0.9)', + borderColor: 'rgba(255,255,255,0.1)', + borderWidth: 1, + padding: [2, 4], + color: '#A1A1AA', + fontSize: 10, + fontFamily: 'JetBrains Mono, monospace', + formatter: (params: any) => { + return params.value ?? '' + }, + }, + }, + axisLine: { show: false }, + axisLabel: { + color: THEME.text, + fontSize: 10, + fontFamily: 'JetBrains Mono, monospace', + formatter: xAxisLabelFormatter, + interval: 0, + }, + axisTick: { show: false }, + splitLine: { + show: true, + lineStyle: { color: 'rgba(255,255,255,0.04)' }, + }, + }, + { + type: 'category', + gridIndex: 1, + data: FULL_DAY_TIMES, + boundaryGap: false, + axisLine: { show: false }, + axisLabel: { show: false }, + axisTick: { show: false }, + splitLine: { show: false }, + }, + ], + yAxis: [ + { + type: 'value', + min: yMin, + max: yMax, + interval: maxDiff || undefined, + splitArea: { show: false }, + axisLine: { show: false }, + axisTick: { show: false }, + splitLine: { lineStyle: { color: THEME.grid } }, + axisPointer: { + label: { + formatter: (params: any) => { + const v = params.value + return typeof v === 'number' ? v.toFixed(2) : '' + }, + }, + }, + axisLabel: { + color: THEME.text, + fontSize: 10, + fontFamily: 'JetBrains Mono, monospace', + formatter: (v: number) => v.toFixed(2), + }, + }, + { + scale: true, + gridIndex: 1, + splitNumber: 2, + axisLine: { show: false }, + axisTick: { show: false }, + splitLine: { show: false }, + axisLabel: { show: false }, + }, + ...(isValidPrice(prevClose) && yMin != null && yMax != null ? [{ + type: 'value' as const, + position: 'right' as const, + gridIndex: 0, + min: yMin, + max: yMax, + interval: maxDiff || undefined, + splitArea: { show: false }, + axisLine: { show: false }, + axisTick: { show: false }, + splitLine: { show: false }, + axisPointer: { + label: { + formatter: (params: any) => { + const v = params.value + if (typeof v !== 'number') return '' + const pct = (v - prevClose) / prevClose * 100 + if (Math.abs(pct) < 0.01) return '0.00%' + return (pct > 0 ? '+' : '') + pct.toFixed(2) + '%' + }, + }, + }, + axisLabel: { + color: THEME.text, + fontSize: 10, + fontFamily: 'JetBrains Mono, monospace', + formatter: (v: number) => { + const pct = (v - prevClose) / prevClose * 100 + if (Math.abs(pct) < 0.01) return '0.00%' + return (pct > 0 ? '+' : '') + pct.toFixed(2) + '%' + }, + }, + }] : []), + ], + series: [ + { + name: '价格', + type: 'line', + data: closes, + smooth: false, + symbol: 'none', + cursor: 'crosshair', + lineStyle: { width: 1.2, color: lineColor }, + areaStyle, + connectNulls: true, + markLine: markLineData.length > 0 ? { symbol: 'none', data: markLineData, animation: false, silent: true } : undefined, + }, + ...(showAvgLine ? [{ + name: '均价', + type: 'line' as const, + data: avgData, + smooth: false, + symbol: 'none', + cursor: 'crosshair', + lineStyle: { width: 1, color: THEME.avgLine }, + connectNulls: true, + }] : []), + { + name: '成交量', + type: 'bar', + data: volumes, + xAxisIndex: 1, + yAxisIndex: 1, + cursor: 'crosshair', + }, + ], + } +} + +export function EChartsIntraday({ data, height = 320, prevClose, date, symbol, onPriceHover, showLimitLines = true, showAvgLine = true }: Props) { + const containerRef = useRef(null) + const chartRef = useRef(null) + const roRef = useRef(null) + const moRef = useRef(null) + const dataRef = useRef(data) + dataRef.current = data + const onPriceHoverRef = useRef(onPriceHover) + onPriceHoverRef.current = onPriceHover + // 全日索引 → 数据数组索引 的映射 (ref 避免重建 chart) + const fullDayToDataIdx = useRef>(new Map()) + + const [infoIdx, setInfoIdx] = useState(data.length - 1) + const [yMode, setYMode] = useState('adaptive') + const avgPrices = useMemo(() => computeAvgPrice(data), [data]) + + // 分时线颜色:基于最新价 vs 昨收 + const lastClose = data.length > 0 ? data[data.length - 1].close : null + const lineIsUp = lastClose != null && prevClose != null ? lastClose > prevClose : true + const lineIsFlat = lastClose != null && prevClose != null ? lastClose === prevClose : false + const lineColor = lineIsFlat ? '#A1A1AA' : lineIsUp ? '#C74040' : '#2D9B65' + const areaFill = lineIsFlat ? 'rgba(180,180,190,0.40)' : lineIsUp ? 'rgba(199,64,64,0.40)' : 'rgba(34,197,94,0.40)' + + useEffect(() => { + setInfoIdx(data.length - 1) + }, [data.length]) + + useEffect(() => { + const el = containerRef.current + if (!el) return + + let chart = chartRef.current + if (!chart) { + chart = echarts.init(el, undefined, { renderer: 'canvas' }) + chartRef.current = chart + // 强制 canvas 使用十字光标,覆盖 ECharts 默认的 pointer + const forceCursor = () => { + const canvases = el.querySelectorAll('canvas') + canvases.forEach(c => { c.style.setProperty('cursor', 'crosshair', 'important') }) + } + forceCursor() + // MutationObserver: ECharts 内部可能重建/修改 canvas 属性,持续强制 cursor + const mo = new MutationObserver(forceCursor) + mo.observe(el, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }) + moRef.current = mo + roRef.current = new ResizeObserver(() => { + chart!.resize() + forceCursor() + }) + roRef.current.observe(el) + + chart.on('updateAxisPointer', (event: any) => { + const axesInfo = event.axesInfo + if (!axesInfo) return + for (const info of Object.values(axesInfo)) { + const val = (info as any)?.value + if (val == null) continue + const fullDayIdx = typeof val === 'number' ? val : -1 + if (fullDayIdx >= 0) { + const dataIdx = fullDayToDataIdx.current.get(fullDayIdx) ?? -1 + setInfoIdx(dataIdx) + const d = dataRef.current + if (dataIdx >= 0 && dataIdx < d.length) { + onPriceHoverRef.current?.(d[dataIdx].close) + } + return + } + } + }) + + chart.on('globalout', () => { + onPriceHoverRef.current?.(null) + }) + } + + if (data.length > 0) { + // 构建全日索引 → 数据索引 的映射 + const timeIndexMap = new Map(FULL_DAY_TIMES.map((t, i) => [t, i])) + const mapping = new Map() + for (let i = 0; i < data.length; i++) { + const timeKey = fmtTime(data[i].datetime) + const fullDayIdx = timeIndexMap.get(timeKey) + if (fullDayIdx !== undefined) { + mapping.set(fullDayIdx, i) + } + } + fullDayToDataIdx.current = mapping + + chart.setOption(buildOption(data, prevClose, avgPrices, lineColor, areaFill, yMode, symbol, showLimitLines, showAvgLine), true) + } else { + chart.clear() + } + }, [data, prevClose, height, lineColor, areaFill, yMode, symbol, showLimitLines, showAvgLine]) + + useEffect(() => { + return () => { + chartRef.current?.off('updateAxisPointer') + chartRef.current?.off('globalout') + moRef.current?.disconnect() + roRef.current?.disconnect() + chartRef.current?.dispose() + chartRef.current = null + moRef.current = null + roRef.current = null + } + }, []) + + const d = infoIdx >= 0 && infoIdx < data.length ? data[infoIdx] : null + const avg = d != null ? avgPrices[infoIdx] : null + const chg = d && prevClose != null ? d.close - prevClose : null + const isUp = chg != null ? chg > 0 : true + const isFlat = chg != null ? chg === 0 : false + const priceClr = isFlat ? '#A1A1AA' : isUp ? '#C74040' : '#2D9B65' + + return ( +
    + {/* 按钮行: 切换式按钮组, 居右 */} + {showLimitLines &&
    +
    + +
    + +
    +
    } +
    + {/* 第一行: 日期 + OHLC */} +
    + {!d && } + {d && ( + <> + {date && {date}} + + {d.open.toFixed(2)} + + {d.high.toFixed(2)} + + {d.low.toFixed(2)} + + {d.close.toFixed(2)} + + )} +
    + {/* 第二行: 价格+均价+量+额 */} +
    + {d && ( + <> + + + {d.close.toFixed(2)} + + {showAvgLine && + + {avg?.toFixed(2)} + } + + {d.volume.toFixed(0)} + + {fmtAmt(d.amount)} + + )} +
    +
    +
    +
    + ) +} diff --git a/frontend/src/components/EmptyState.tsx b/frontend/src/components/EmptyState.tsx new file mode 100644 index 0000000..3132e90 --- /dev/null +++ b/frontend/src/components/EmptyState.tsx @@ -0,0 +1,20 @@ +import { type LucideIcon, Construction } from 'lucide-react' + +interface Props { + icon?: LucideIcon + title: string + hint?: string +} + +// §6.0.5 四态评审 — empty 状态:图示 + 引导,而不是一句"暂无数据" +export function EmptyState({ icon: Icon = Construction, title, hint }: Props) { + return ( +
    +
    + +

    {title}

    + {hint &&

    {hint}

    } +
    +
    + ) +} diff --git a/frontend/src/components/EndpointTestDialog.tsx b/frontend/src/components/EndpointTestDialog.tsx new file mode 100644 index 0000000..8df5444 --- /dev/null +++ b/frontend/src/components/EndpointTestDialog.tsx @@ -0,0 +1,259 @@ +import { useState } from 'react' +import { useQuery, useQueryClient } from '@tanstack/react-query' +import { motion, AnimatePresence } from 'framer-motion' +import { Wifi, Play, Loader2, X, Check, Crown } from 'lucide-react' +import { api, type EndpointItem } from '@/lib/api' +import { QK } from '@/lib/queryKeys' + +interface EpResult { + ok: boolean + median_ms?: number | null + min_ms?: number | null + max_ms?: number | null + rounds?: number + success?: number + error?: string +} + +export function EndpointTestDialog({ hasKey, currentEndpoint, onClose }: { hasKey: boolean; currentEndpoint: string; onClose: () => void }) { + const qc = useQueryClient() + const [results, setResults] = useState>({}) + const [testing, setTesting] = useState>({}) + const [switching, setSwitching] = useState(null) + + // 动态加载端点清单 —— 前端无法跨域直连 tickflow.org,走后端代理 + const { data, isLoading } = useQuery({ + queryKey: QK.endpoints, + queryFn: api.listEndpoints, + staleTime: 5 * 60 * 1000, + }) + + const endpoints = data?.endpoints ?? [] + const isFallback = data?.source === 'fallback' + const testRounds = data?.testRounds + + async function testOne(url: string) { + setTesting(prev => ({ ...prev, [url]: true })) + setResults(prev => ({ ...prev, [url]: null })) + try { + const res = await api.testEndpoint(url, testRounds) + setResults(prev => ({ ...prev, [url]: res })) + } catch (e: any) { + setResults(prev => ({ ...prev, [url]: { ok: false, error: e?.message ?? '请求失败' } })) + } finally { + setTesting(prev => ({ ...prev, [url]: false })) + } + } + + async function testAll() { + setResults({}) + await Promise.all(endpoints.map(ep => testOne(ep.url))) + } + + const anyTesting = Object.values(testing).some(Boolean) + const isFree = !hasKey + const currentLabel = endpoints.find(ep => ep.url === currentEndpoint)?.label ?? currentEndpoint + + async function applyEndpoint(url: string) { + setSwitching(url) + try { + await api.switchEndpoint(url) + await qc.invalidateQueries({ queryKey: QK.settings }) + onClose() + } catch { + // 错误由 query 处理 + } finally { + setSwitching(null) + } + } + + return ( + +
    + + + {/* 顶栏 */} +
    +
    + + 端点测速 +
    +
    + {isFree && ( + Free 模式 + )} + + +
    +
    + + {/* 当前使用 */} +
    + + 当前使用 + {currentLabel} + {currentEndpoint.replace('https://', '')} +
    + + {/* Free 模式提示 —— 以下均为 Starter+ 付费端点 */} + {isFree && ( +
    + + 以下均为 Starter+ 付费端点,Free 模式不可使用。配置 API Key 后可自动切换并测速选优。 + +
    + )} + + {/* 端点列表 —— 可滚动区,顶栏/当前使用/底栏始终可见 */} +
    + {isLoading ? ( +
    + + 加载端点列表… +
    + ) : endpoints.length === 0 ? ( +
    未能加载端点列表
    + ) : ( + endpoints.map(ep => ( + + )) + )} +
    + + {isFallback ? ( + 远程获取失败,显示内置列表 + ) : null} +
    +
    +
    + ) +} + +function EpRow({ ep, result, testing, isCurrent, isFree, switching, onApply }: { + ep: EndpointItem + result: EpResult | null + testing?: boolean + isCurrent?: boolean + isFree?: boolean + switching: string | null + onApply: (url: string) => void +}) { + const isError = result && !result.ok + const canApply = result?.ok && !testing && !isCurrent + const isPremium = ep.premium === true + const median = result?.median_ms + + return ( +
    +
    + {/* 第1行:label + 徽章(左) / 中位延迟(右) */} +
    +
    + {ep.label} + {isPremium && ( + + + 专线 + + )} + {isCurrent && ( + 使用中 + )} +
    + {/* 中位延迟 —— 测试中/前/后都占位,避免高度跳动 */} + + {isFree ? ( + // Free 模式:普通付费端点需 Starter+,premium 端点需 Expert+ + + {isPremium ? 'Expert+' : 'Starter+'} + + ) : testing ? ( + 测试中… + ) : result && result.ok && median != null ? ( + + {median} ms + + ) : result && !result.ok ? ( + {result.error ?? '不可达'} + ) : ( + + )} + +
    + + {/* 第2行:description */} + {ep.description} + + {/* 第3行:URL(左) / min~max·成功率(右) —— 副信息始终占位,行数不变 */} +
    + {ep.url.replace('https://', '')} + + {result && result.ok && result.min_ms != null + ? `${result.min_ms}~${result.max_ms} · ${result.success}/${result.rounds}` + : '\u00A0'} + +
    +
    + + {/* 应用按钮区域 —— Free 模式不可用任何付费端点 */} + {isFree ? null : isPremium ? ( + // 专线端点:需 Expert 及以上套餐权限,不可应用 + + + Expert+ + + ) : canApply ? ( + + ) : null} +
    + ) +} diff --git a/frontend/src/components/ExtDimensionAnalysis.tsx b/frontend/src/components/ExtDimensionAnalysis.tsx new file mode 100644 index 0000000..37fb0b0 --- /dev/null +++ b/frontend/src/components/ExtDimensionAnalysis.tsx @@ -0,0 +1,436 @@ +import { useMemo, useState, type ComponentType } from 'react' +import { useQuery } from '@tanstack/react-query' +import { + BarChart3, + CalendarDays, + Database, + Layers3, + Search, + Tags, + TrendingUp, + Users, +} from 'lucide-react' +import { PageHeader } from '@/components/PageHeader' +import { api, type AnalysisColumn, type ExtDataConfig, type ExtDataField } from '@/lib/api' +import { QK } from '@/lib/queryKeys' + +interface DimensionAnalysisProps { + menuId?: string + title?: string + subtitle?: string + kindLabel?: string + emptyHint?: string + accentClass?: string + keywords?: string[] + fallbackFieldNames?: string[] +} + +interface DimensionGroup { + key: string + count: number + rows: Record[] + metrics: Record +} + +const PAGE_LIMIT = 5000 +const SEPARATORS = /[、,,;;|/\s]+/ + +function normalizeText(v: unknown): string { + if (v == null) return '' + return String(v).trim() +} + +function fieldLabel(fields: ExtDataField[], name: string): string { + return fields.find(f => f.name === name)?.label || name +} + +function isNumericField(f: ExtDataField) { + return f.dtype === 'int' || f.dtype === 'float' +} + +function scoreConfig(config: ExtDataConfig, keywords: string[]) { + const haystack = [ + config.id, + config.label, + config.description ?? '', + ...config.fields.flatMap(f => [f.name, f.label]), + ].join(' ').toLowerCase() + return keywords.reduce((n, k) => n + (haystack.includes(k.toLowerCase()) ? 1 : 0), 0) +} + +function pickDefaultConfig(configs: ExtDataConfig[], keywords: string[]) { + const ranked = [...configs].sort((a, b) => scoreConfig(b, keywords) - scoreConfig(a, keywords)) + return ranked[0]?.id ?? '' +} + +function pickDefaultDimensionField(config: ExtDataConfig | undefined, fallbackFieldNames: string[]) { + if (!config) return '' + const fields = config.fields.filter(f => f.name !== 'symbol' && f.name !== 'code') + for (const name of fallbackFieldNames) { + const matched = fields.find(f => f.name.toLowerCase().includes(name) || f.label.toLowerCase().includes(name)) + if (matched) return matched.name + } + return fields.find(f => !isNumericField(f))?.name ?? fields[0]?.name ?? '' +} + +function formatNumber(v: unknown, digits = 2) { + if (typeof v !== 'number' || !Number.isFinite(v)) return '—' + return v.toLocaleString('zh-CN', { maximumFractionDigits: digits }) +} + +function formatValue(v: unknown, col?: AnalysisColumn) { + if (v == null || v === '') return '—' + if (typeof v === 'boolean') return v ? '是' : '否' + if (typeof v !== 'number') return String(v) + + const digits = col?.precision ?? (col?.type === 'number' || col?.type === 'amount' || col?.type === 'percent' ? 2 : 2) + if (col?.type === 'percent') return `${formatNumber(v, digits)}%` + if (col?.type === 'amount' || col?.format === 'amount') return formatNumber(v, digits) + return formatNumber(v, digits) +} + +function splitDimensionValues(value: unknown) { + const text = normalizeText(value) + if (!text) return [] + return text.split(SEPARATORS).map(s => s.trim()).filter(Boolean) +} + +function StatCard({ label, value, hint, icon: Icon }: { + label: string + value: string | number + hint: string + icon: ComponentType<{ className?: string }> +}) { + return ( +
    +
    + {label} + +
    +
    {value}
    +
    {hint}
    +
    + ) +} + +function columnsFromFields(fields: ExtDataField[], dimensionField: string, rows: Record[]) { + const numericFields = fields.filter(f => isNumericField(f) && rows.some(r => typeof r[f.name] === 'number')).slice(0, 4) + return [ + ...fields.filter(f => ['symbol', 'code', 'name', '股票简称', '股票代码'].includes(f.name)), + ...fields.filter(f => f.name === dimensionField), + ...numericFields, + ] + .filter((f, i, arr) => arr.findIndex(x => x.name === f.name) === i) + .map(f => ({ + field: f.name, + label: f.label || f.name, + type: isNumericField(f) ? 'number' : 'string', + precision: f.dtype === 'float' ? 2 : null, + sortable: isNumericField(f), + visible: true, + })) +} + +function aggregate(rows: Record[], col: AnalysisColumn) { + if (col.field === '__count') return rows.length + const values = rows.map(r => r[col.field]).filter((v): v is number => typeof v === 'number' && Number.isFinite(v)) + if (!values.length) return null + switch (col.aggregate) { + case 'sum': return values.reduce((a, b) => a + b, 0) + case 'min': return Math.min(...values) + case 'max': return Math.max(...values) + case 'avg': + default: + return values.reduce((a, b) => a + b, 0) / values.length + } +} + +export function ExtDimensionAnalysis({ + menuId, + title, + subtitle, + kindLabel = '维度', + emptyHint = '还没有可用于分析的扩展数据。', + accentClass = 'bg-[radial-gradient(circle_at_top_right,rgba(59,130,246,0.16),transparent_36%)]', + keywords = [], + fallbackFieldNames = [], +}: DimensionAnalysisProps) { + const configs = useQuery({ queryKey: QK.extData, queryFn: api.extDataList }) + const menuQuery = useQuery({ + queryKey: QK.analysisMenu(menuId ?? ''), + queryFn: () => api.analysisMenu(menuId!), + enabled: !!menuId, + }) + const menu = menuQuery.data + + const [selectedConfigId, setSelectedConfigId] = useState('') + const [dimensionField, setDimensionField] = useState('') + const [search, setSearch] = useState('') + const [selectedGroup, setSelectedGroup] = useState(null) + + const availableConfigs = configs.data?.items ?? [] + const activeConfigId = menu?.data_source || selectedConfigId || pickDefaultConfig(availableConfigs, keywords) + const activeConfig = availableConfigs.find(c => c.id === activeConfigId) + const activeDimensionField = menu?.dimension_field || dimensionField || pickDefaultDimensionField(activeConfig, fallbackFieldNames) + const activeTitle = menu?.label || title || '扩展分析' + const activeKindLabel = menu?.template === 'table' ? '数据' : kindLabel + + const configuredColumns = useMemo(() => { + const cols = menu?.detail_columns?.filter(c => c.visible !== false) ?? [] + return cols.length > 0 ? cols : null + }, [menu?.detail_columns]) + const requestedColumns = useMemo(() => { + const cols = [activeDimensionField, ...(configuredColumns?.map(c => c.field) ?? [])].filter(Boolean) + return Array.from(new Set(cols)) + }, [activeDimensionField, configuredColumns]) + const columnsKey = requestedColumns.join(',') + + const rowsQuery = useQuery({ + queryKey: QK.extDataRows(activeConfigId, undefined, PAGE_LIMIT, columnsKey), + queryFn: () => api.extDataRows(activeConfigId, { limit: PAGE_LIMIT, columns: requestedColumns }), + enabled: !!activeConfigId, + }) + + const rows = rowsQuery.data?.rows ?? [] + const baseFields = activeConfig?.fields ?? rowsQuery.data?.fields ?? [] + const fields = rows.some(r => r.name != null) && !baseFields.some(f => f.name === 'name') + ? [...baseFields, { name: 'name', dtype: 'string', label: '名称' }] + : baseFields + const dimensionOptions = fields.filter(f => f.name !== 'symbol' && f.name !== 'code') + const displayColumns = configuredColumns ?? columnsFromFields(fields, activeDimensionField, rows) + const groupColumns = (menu?.group_columns?.length ? menu.group_columns : [ + { field: '__dimension', label: activeKindLabel }, + { field: '__count', label: '股票数', type: 'number' as const, sortable: true }, + ]).filter(c => c.visible !== false) + + const sortedRows = useMemo(() => { + if (!menu?.default_sort?.field) return rows + const factor = menu.default_sort.order === 'asc' ? 1 : -1 + return [...rows].sort((a, b) => { + const av = a[menu.default_sort!.field] + const bv = b[menu.default_sort!.field] + if (typeof av === 'number' && typeof bv === 'number') return (av - bv) * factor + return String(av ?? '').localeCompare(String(bv ?? '')) * factor + }) + }, [rows, menu?.default_sort]) + + const groups = useMemo(() => { + if (!activeDimensionField || menu?.template === 'table' || menu?.template === 'ranking') return [] + const map = new Map[]>() + for (const row of sortedRows) { + const values = splitDimensionValues(row[activeDimensionField]) + for (const value of values) { + const item = map.get(value) ?? [] + item.push(row) + map.set(value, item) + } + } + return [...map.entries()] + .map(([key, itemRows]) => ({ + key, + count: itemRows.length, + rows: itemRows, + metrics: Object.fromEntries(groupColumns.map(col => [col.field, aggregate(itemRows, col)])), + })) + .sort((a, b) => b.count - a.count) + }, [sortedRows, activeDimensionField, groupColumns, menu?.template]) + + const filteredGroups = useMemo(() => { + const q = search.trim().toLowerCase() + if (!q) return groups + return groups.filter(g => g.key.toLowerCase().includes(q)) + }, [groups, search]) + + const currentGroup = filteredGroups.find(g => g.key === selectedGroup) ?? filteredGroups[0] + const tableRows = menu?.template === 'table' || menu?.template === 'ranking' ? sortedRows : (currentGroup?.rows ?? []) + const coveredSymbols = useMemo(() => { + const set = new Set() + rows.forEach(r => { if (r.symbol) set.add(String(r.symbol)) }) + return set.size + }, [rows]) + const missingConfiguredColumns = displayColumns.filter(c => rows.length > 0 && !Object.prototype.hasOwnProperty.call(rows[0], c.field)) + + return ( + <> + + + +
    + )} + /> + +
    +
    +
    +
    + + 扩展数据驱动 · 菜单可配置 · 列动态渲染 +
    +

    {activeTitle}

    +

    + 页面按分析菜单配置读取扩展数据源,使用分组字段生成榜单,并严格按照 detail_columns 渲染明细列。 +

    +
    +
    + +
    +
    + + {configs.isLoading || menuQuery.isLoading ? ( +
    加载配置中…
    + ) : menuQuery.isError ? ( +
    分析菜单不存在或已删除。
    + ) : !activeConfig ? ( +
    + +
    {emptyHint}
    +
    请先在“数据”页面新增扩展数据,并在“扩展分析”中创建分析菜单。
    +
    + ) : ( + <> +
    + + + + +
    + + {missingConfiguredColumns.length > 0 && ( +
    + 菜单中有字段在当前数据中不存在:{missingConfiguredColumns.map(c => c.field).join('、')} +
    + )} + +
    + {menu?.template !== 'table' && menu?.template !== 'ranking' && ( +
    +
    +
    +

    分组榜单

    +

    按覆盖标的数量排序

    +
    + Top {Math.min(filteredGroups.length, 100)} +
    +
    +
    + + { setSearch(e.target.value); setSelectedGroup(null) }} + placeholder={`搜索${activeKindLabel}`} + className="h-8 w-full rounded-btn border border-border bg-base pl-8 pr-3 text-xs text-foreground placeholder:text-muted/50 focus:outline-none focus:border-accent/50" + /> +
    +
    +
    + {filteredGroups.length === 0 ? ( +
    没有可展示的分组
    + ) : filteredGroups.slice(0, 100).map((group, i) => { + const active = currentGroup?.key === group.key + return ( + + ) + })} +
    +
    + )} + +
    +
    +
    +
    +

    {menu?.template === 'table' || menu?.template === 'ranking' ? '明细列表' : currentGroup?.key ?? `选择${activeKindLabel}`}

    + {tableRows.length} 条 +
    +

    列来自菜单 detail_columns:{displayColumns.map(f => f.label || f.field).join(' / ') || '暂无字段'}

    +
    +
    + + {rowsQuery.data?.date ?? '当前快照'} +
    +
    + +
    + + + + {displayColumns.map(col => ( + + ))} + + + + {rowsQuery.isLoading ? ( + + ) : tableRows.length === 0 ? ( + + ) : tableRows.slice(0, 300).map((row, i) => ( + + {displayColumns.map(col => ( + + ))} + + ))} + +
    {col.label || col.field}
    加载数据中…
    暂无明细数据
    + {formatValue(row[col.field], col)} +
    +
    + + {tableRows.length > 300 && ( +
    仅展示前 300 条明细,共 {tableRows.length} 条
    + )} +
    +
    + + )} +
    + + ) +} diff --git a/frontend/src/components/Layout.tsx b/frontend/src/components/Layout.tsx new file mode 100644 index 0000000..5757a3a --- /dev/null +++ b/frontend/src/components/Layout.tsx @@ -0,0 +1,449 @@ +import { NavLink, Outlet, useNavigate } from 'react-router-dom' +import { useQuery, useQueryClient } from '@tanstack/react-query' +import { motion } from 'framer-motion' +import { useQuoteStream } from '@/lib/useQuoteStream' +import { ToastContainer } from '@/components/Toast' +import { + useCapabilities, + useSettings, + usePreferences, + useQuoteStatus, + useVersion, +} from '@/lib/useSharedQueries' +import { + useToggleRealtimeQuotes, +} from '@/lib/useSharedMutations' +import { QK } from '@/lib/queryKeys' +import { + Star, + ScanSearch, + History, + FileText, + Settings, + Key, + Database, + Timer, + LayoutDashboard, + Tags, + TrendingUp, + Flame, + BarChart3, + Sparkles, + Layers3, + Landmark, + Cable, + RadioTower, +} from 'lucide-react' +import { Logo } from './Logo' +import { api, type IndexQuote } from '@/lib/api' +import { cn } from '@/lib/cn' + +// 品牌色 — 只用于 logo / brand 区域,不影响功能语义色 +const BRAND = '#8B5CF6' + +const CORE_INDEXES = [ + { symbol: '000001.SH', name: '上证指数' }, + { symbol: '399001.SZ', name: '深证成指' }, + { symbol: '399006.SZ', name: '创业板指' }, + { symbol: '000680.SH', name: '科创综指' }, +] as const + +type CoreIndex = (typeof CORE_INDEXES)[number] + +const nav = [ + { to: '/', label: '看板', icon: LayoutDashboard }, + { to: '/watchlist', label: '自选', icon: Star }, + { to: '/screener', label: '策略', icon: ScanSearch }, + { to: '/backtest', label: '回测', icon: History }, + { to: '/limit-ladder', label: '连板梯队', icon: Flame }, + { to: '/concept-analysis', label: '概念分析', icon: Layers3 }, + { to: '/industry-analysis', label: '行业分析', icon: Landmark }, + { to: '/stock-analysis', label: '个股分析', icon: TrendingUp }, + { to: '/financials', label: '财务', icon: FileText }, + { to: '/indices', label: '指数', icon: BarChart3 }, + { to: '/trading', label: '交易', icon: Cable }, + { to: '/monitor', label: '监控通知', icon: RadioTower }, + { to: '/data', label: '数据', icon: Database }, +] as const + +function fmtIndexValue(v: number | null | undefined) { + if (v == null || Number.isNaN(Number(v))) return '--' + return Number(v).toFixed(2) +} + +function fmtIndexPct(v: number | null | undefined) { + if (v == null || Number.isNaN(Number(v))) return '--' + return `${Number(v) >= 0 ? '+' : ''}${Number(v).toFixed(2)}%` +} + +function indexPctClass(v: number | null | undefined) { + if (v == null || Number.isNaN(Number(v))) return 'text-muted' + return Number(v) >= 0 ? 'text-bull' : 'text-bear' +} + +function SidebarIndexQuotes({ rows, items }: { rows: IndexQuote[] | undefined; items: CoreIndex[] }) { + if (items.length === 0) return null + const quoteBySymbol = new Map((rows ?? []).map(q => [q.symbol, q])) + return ( +
    + {items.map(item => { + const q = quoteBySymbol.get(item.symbol) + const value = q?.last_price ?? q?.close + const pct = q?.change_pct + return ( + +
    + {item.name} + {fmtIndexPct(pct)} +
    +
    + {fmtIndexValue(value)} +
    +
    + ) + })} +
    + ) +} + +// ===== 档位卡片 ===== +function TierBadge({ label, hasKey }: { label: string; hasKey?: boolean }) { + const base = label.split(' ')[0].split('+')[0].toLowerCase() + const isFree = base === 'free' || !label + + const tierConfig: Record = { + free: { + desc: '基础日K · 单股查询', + tagBg: { background: 'rgba(113,113,122,0.3)' }, + dotStyle: { background: '#71717a' }, + labelTextStyle: { color: '#a1a1aa' }, + }, + starter: { + desc: '批量同步 · 行情池', + tagBg: { background: 'rgba(59,130,246,0.2)' }, + dotStyle: { background: '#3b82f6' }, + labelTextStyle: { color: '#60a5fa' }, + }, + pro: { + desc: '分钟K · 实时行情 · 盘口', + tagBg: { background: 'linear-gradient(135deg, rgba(168,85,247,0.2), rgba(124,58,237,0.15))' }, + dotStyle: { background: 'linear-gradient(135deg, #a855f7, #7c3aed)' }, + labelTextStyle: { background: 'linear-gradient(135deg, #c084fc, #a855f7)', WebkitBackgroundClip: 'text', backgroundClip: 'text', color: 'transparent' }, + }, + expert: { + desc: 'WebSocket · 财务数据', + tagBg: { background: 'linear-gradient(135deg, rgba(59,130,246,0.2), rgba(168,85,247,0.2), rgba(245,158,11,0.2))' }, + dotStyle: { background: 'linear-gradient(135deg, #3b82f6, #a855f7, #f59e0b)' }, + labelTextStyle: { background: 'linear-gradient(135deg, #60a5fa, #c084fc, #fbbf24)', WebkitBackgroundClip: 'text', backgroundClip: 'text', color: 'transparent' }, + }, + } + + const t = tierConfig[base] || tierConfig.free + + return ( + +
    +
    +
    +
    + +
    +
    +
    + TickFlow + +
    +
    + {isFree && !hasKey ? '配置 Key 解锁更多能力' : t.desc} +
    +
    + + {label || 'Free'} + + +
    + +
    + + ) +} + +function AIConfigBadge({ configured, model }: { configured?: boolean; model?: string }) { + return ( + +
    +
    +
    +
    + +
    +
    +
    + AI 配置 + +
    +
    + {configured ? (model || '已接入模型') : '接入策略生成模型'} +
    +
    + +
    +
    + + ) +} + +export function Layout() { + // ===== 共享 hooks (替代内联 useQuery) ===== + const { data: caps } = useCapabilities() + const { data: settingsState } = useSettings() + const { data: versionData } = useVersion() + const { data: prefs } = usePreferences() + const { data: quoteStatus } = useQuoteStatus() + const { data: analysisMenus } = useQuery({ + queryKey: QK.analysisMenus, + queryFn: api.analysisMenus, + }) + + const qc = useQueryClient() + const navigate = useNavigate() + const version = versionData?.version + const realtimeEnabled = prefs?.realtime_quotes_enabled ?? false + const indicesPinned = prefs?.indices_nav_pinned ?? true + const sidebarIndexSymbols = prefs?.sidebar_index_symbols ?? CORE_INDEXES.map(p => p.symbol) + const sidebarIndexes = CORE_INDEXES.filter(item => sidebarIndexSymbols.includes(item.symbol)) + // 卡片数据:固定显示时也拉取(即使实时行情关闭) + const showSidebarQuotes = indicesPinned || realtimeEnabled + const { data: sidebarIndexQuotes } = useQuery({ + queryKey: [...QK.indexQuotes, 'sidebar', sidebarIndexSymbols.join(',')] as const, + queryFn: () => api.indexQuotes(sidebarIndexes.map(p => p.symbol)), + enabled: showSidebarQuotes && sidebarIndexes.length > 0, + placeholderData: (prev) => prev, + }) + + // SSE: 行情更新时自动刷新相关 queries + 告警通知 + useQuoteStream(realtimeEnabled, prefs?.sse_refresh_pages) + + const toggleQuote = useToggleRealtimeQuotes() + const isRunning = quoteStatus?.running ?? false + const isTrading = quoteStatus?.is_trading_hours ?? false + const isFreeTier = (caps?.label ?? '').toLowerCase().startsWith('free') + + // 合并内置页面 + 可见的扩展分析菜单 + const analysisNav = (analysisMenus?.items ?? []) + .filter(m => m.visible) + .map(m => ({ to: `/analysis/${m.id}`, label: m.label, icon: m.icon === 'tags' ? Tags : BarChart3 })) + + const allNav = [...nav, ...analysisNav] + const savedOrder = prefs?.nav_order ?? [] + + const navItems = savedOrder.length > 0 + ? (() => { + const byTo = new Map(allNav.map(n => [n.to, n])) + const ordered = savedOrder + .map(id => byTo.get(id) ?? byTo.get(`/analysis/${id}`)) + .filter(Boolean) + const seen = new Set(ordered.map(n => n!.to)) + return [...ordered as typeof allNav, ...allNav.filter(n => !seen.has(n.to))] + })() + : allNav + + const hiddenIds = new Set(prefs?.nav_hidden ?? []) + const visibleNavItems = navItems.filter(n => !hiddenIds.has(n.to) && !hiddenIds.has(n.to.replace(/^\/analysis\//, ''))) + + const handleToggle = async (enabled: boolean) => { + // 开启时重新校验档位 + if (enabled) { + const fresh = await qc.fetchQuery({ + queryKey: QK.capabilities, + queryFn: api.capabilities, + }) + if ((fresh.label ?? '').toLowerCase().startsWith('free')) return + } + await toggleQuote.mutateAsync(enabled) + // 仅在交易时段立即获取一次行情 + if (enabled && isTrading) { + api.intradayRefresh().catch(() => {}) + } + } + + return ( +
    + + + + + + +
    + ) +} diff --git a/frontend/src/components/ListColumnCustomizer.tsx b/frontend/src/components/ListColumnCustomizer.tsx new file mode 100644 index 0000000..e803de6 --- /dev/null +++ b/frontend/src/components/ListColumnCustomizer.tsx @@ -0,0 +1,714 @@ +/** + * 通用列表列自定义组件。 + * + * 布局: + * - 上半区「已启用」:已启用的列,@dnd-kit 拖拽排序 + * - 下半区「内置列」:按业务分组折叠 + * - 底部「扩展数据列」:复用 ext_data schema,按需添加字段 + */ +import React, { useState, useCallback, useEffect, useMemo } from 'react' +import { motion, AnimatePresence } from 'framer-motion' +import { + DndContext, closestCenter, KeyboardSensor, PointerSensor, + useSensor, useSensors, type DragEndEvent, +} from '@dnd-kit/core' +import { + arrayMove, SortableContext, sortableKeyboardCoordinates, + useSortable, verticalListSortingStrategy, +} from '@dnd-kit/sortable' +import { CSS } from '@dnd-kit/utilities' +import { X, GripVertical, Plus, ChevronDown, ChevronRight, Database, Settings2, Search, Eye, EyeOff } from 'lucide-react' +import { api } from '@/lib/api' +import { useQuery } from '@tanstack/react-query' +import { QK } from '@/lib/queryKeys' +import type { ColumnConfig, ColumnGroup, ExtColumnDisplayConfig, CandleColumnConfig } from '@/lib/list-columns' +import { resolveCandleConfig } from '@/lib/list-columns' + +interface ListColumnCustomizerProps { + columns: ColumnConfig[] + groups: ColumnGroup[] + onChange: (columns: ColumnConfig[]) => void + open: boolean + onClose: () => void + title?: string + builtinSectionLabel?: string + extColumnAlign?: 'left' | 'center' | 'right' + extFieldFilter?: (field: { name: string; label: string; type: string }) => boolean +} + +function SortableActiveCol({ col, onRemove, onConfig, configOpen, extTableLabel, extConfig, candleConfig: candlePanel, strategiesConfig }: { + col: ColumnConfig + onRemove: (id: string) => void + onConfig: (id: string | null) => void + configOpen: boolean + extTableLabel: string + extConfig: React.ReactNode + candleConfig: React.ReactNode + strategiesConfig: React.ReactNode +}) { + const { + attributes, listeners, setNodeRef, transform, transition, isDragging, + } = useSortable({ id: col.id }) + const isExt = col.source.type === 'ext' + const isCandle = col.source.type === 'builtin' && col.source.key === 'candle' + const isStrategies = col.source.type === 'builtin' && col.source.key === 'strategies' + const hasConfig = isExt || isCandle || isStrategies + + return ( + <> +
    + + + + + {isExt && col.source.type === 'ext' + ? `${col.label}(${extTableLabel})` + : col.label} + + {hasConfig && ( + + )} + +
    + {hasConfig && configOpen && (isExt ? extConfig : isCandle ? candlePanel : strategiesConfig)} + + ) +} + +export function ListColumnCustomizer({ + columns, + groups, + onChange, + open, + onClose, + title = '自定义列', + builtinSectionLabel = '内置列', + extColumnAlign = 'center', + extFieldFilter, +}: ListColumnCustomizerProps) { + const extSchema = useQuery({ + queryKey: QK.extDataSchemaAll, + queryFn: api.extDataSchemaAll, + enabled: open, + staleTime: 60_000, + }) + + const [searchQuery, setSearchQuery] = useState('') + const [expandedGroups, setExpandedGroups] = useState>(new Set()) + const [configOpenId, setConfigOpenId] = useState(null) + const [expandedTables, setExpandedTables] = useState>(new Set()) + + const colById = useMemo(() => new Map(columns.map(c => [c.id, c])), [columns]) + const keyToId = useMemo(() => { + const m = new Map() + for (const c of columns) { + if (c.source.type === 'builtin' || c.source.type === 'computed') m.set(c.source.key, c.id) + } + return m + }, [columns]) + + const activeCols = useMemo(() => columns.filter(c => !c.pinned && c.visible), [columns]) + + const toggleVisible = useCallback((colId: string) => { + onChange(columns.map(c => + c.id === colId && !c.pinned ? { ...c, visible: !c.visible } : c + )) + }, [columns, onChange]) + + const sensors = useSensors( + useSensor(PointerSensor, { activationConstraint: { distance: 5 } }), + useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }), + ) + + const handleDragEnd = useCallback((event: DragEndEvent) => { + const { active, over } = event + if (!over || active.id === over.id) return + const reorderCols = columns.filter(c => !c.pinned) + const pinnedCols = columns.filter(c => c.pinned) + const ids = reorderCols.map(c => c.id) + const oldIdx = ids.indexOf(active.id as string) + const newIdx = ids.indexOf(over.id as string) + if (oldIdx < 0 || newIdx < 0) return + const reordered = arrayMove(reorderCols, oldIdx, newIdx) + onChange([...pinnedCols, ...reordered]) + }, [columns, onChange]) + + const addExtColumn = useCallback((configId: string, fieldName: string, fieldLabel?: string) => { + const colId = `ext:${configId}:${fieldName}` + if (columns.some(c => c.id === colId)) { + toggleVisible(colId) + return + } + const newCol: ColumnConfig = { + id: colId, + source: { type: 'ext', configId, fieldName, fieldLabel }, + label: fieldLabel || fieldName, + visible: true, + align: extColumnAlign, + } + const actionIdx = columns.findIndex(c => c.id === 'builtin:action') + if (actionIdx >= 0) { + const next = [...columns] + next.splice(actionIdx, 0, newCol) + onChange(next) + } else { + onChange([...columns, newCol]) + } + }, [columns, extColumnAlign, onChange, toggleVisible]) + + const hideColumn = useCallback((colId: string) => { + onChange(columns.map(c => c.id === colId ? { ...c, visible: false } : c)) + }, [columns, onChange]) + + const updateExtDisplay = useCallback((colId: string, patch: Partial) => { + onChange(columns.map(c => { + if (c.id !== colId) return c + return { ...c, extDisplay: { displayMode: 'tag', ...(c.extDisplay || {}), ...patch } } + })) + }, [columns, onChange]) + + const resetExtDisplay = useCallback((colId: string) => { + onChange(columns.map(c => { + if (c.id !== colId) return c + const { extDisplay, ...rest } = c + return rest + })) + }, [columns, onChange]) + + const updateCandleConfig = useCallback((colId: string, patch: Partial) => { + onChange(columns.map(c => { + if (c.id !== colId) return c + return { ...c, candleConfig: { ...c.candleConfig, ...patch } } + })) + }, [columns, onChange]) + + const resetCandleConfig = useCallback((colId: string) => { + onChange(columns.map(c => { + if (c.id !== colId) return c + const { candleConfig, ...rest } = c + return rest + })) + }, [columns, onChange]) + + const toggleGroup = useCallback((groupId: string) => { + setExpandedGroups(prev => { + const next = new Set(prev) + if (next.has(groupId)) next.delete(groupId) + else next.add(groupId) + return next + }) + }, []) + + const toggleTableExpand = useCallback((tableId: string) => { + setExpandedTables(prev => { + const next = new Set(prev) + if (next.has(tableId)) next.delete(tableId) + else next.add(tableId) + return next + }) + }, []) + + const extTables = extSchema.data?.items ?? [] + const extTableLabelMap = new Map(extTables.map(t => [t.id, t.label])) + + const query = searchQuery.trim().toLowerCase() + const filteredGroups = useMemo(() => { + if (!query) return groups + return groups.filter(g => + g.label.includes(query) || + g.keys.some(k => { + const id = keyToId.get(k) + return id && (colById.get(id)?.label ?? '').toLowerCase().includes(query) + }) + ) + }, [groups, query, keyToId, colById]) + + useEffect(() => { + if (!open) { setConfigOpenId(null); setSearchQuery('') } + }, [open]) + + useEffect(() => { + if (query) setExpandedGroups(new Set(filteredGroups.map(g => g.id))) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [query]) + + const renderExtConfig = (col: ColumnConfig) => ( + +
    + + {(col.extDisplay?.displayMode ?? 'tag') === 'tag' && ( + + )} + + {(col.extDisplay?.displayMode ?? 'tag') === 'tag' && ( + + )} + {(col.extDisplay?.displayMode ?? 'tag') === 'tag' && (col.extDisplay?.maxTags ?? 0) > 0 && ( +
    + 显示位置 +
    + {Array.from({ length: col.extDisplay!.maxTags! }, (_, i) => { + const hidden = col.extDisplay?.hiddenIndices?.includes(i) + return ( + + ) + })} +
    +
    + )} + {(col.extDisplay?.displayMode ?? 'tag') === 'tag' && ( + + )} + {col.extDisplay && ( +
    + +
    + )} +
    +
    + ) + + // 策略列配置(精简版:仅显示数量/位置/排列方向,复用 extDisplay 存储) + const renderStrategiesConfig = (col: ColumnConfig) => ( + +
    + + {(col.extDisplay?.maxTags ?? 0) > 0 && ( +
    + 显示位置 +
    + {Array.from({ length: col.extDisplay!.maxTags! }, (_, i) => { + const hidden = col.extDisplay?.hiddenIndices?.includes(i) + return ( + + ) + })} +
    +
    + )} + + {col.extDisplay && ( +
    + +
    + )} +
    +
    + ) + + const renderCandleConfig = (col: ColumnConfig) => { + const cfg = resolveCandleConfig(col.candleConfig) + // 数值输入:空字符串回退到默认值,便于清空重输 + const numInput = ( + field: keyof CandleColumnConfig, + label: string, + ) => ( + + ) + return ( + +
    + {numInput('days', '日k天数')} + {numInput('enabledWidth', '开启宽度')} + {numInput('enabledHeight', '开启高度')} + {numInput('disabledWidth', '收起宽度')} + {numInput('disabledHeight', '收起高度')} +
    + 宽度 40–300 / 高度 32–200 / 天数 1–60,越界自动钳制到边界 +
    + {col.candleConfig && ( +
    + +
    + )} +
    +
    + ) + } + + const renderCheckbox = (checked: boolean) => ( + + + + + + ) + + const renderBuiltinRow = (col: ColumnConfig) => ( + + ) + + const renderExtFieldRow = (configId: string, field: { name: string; label: string; type: string }) => { + const colId = `ext:${configId}:${field.name}` + const existing = columns.find(c => c.id === colId) + const checked = !!existing?.visible + return ( + + ) + } + + return ( + + {open && ( +
    + + +
    +

    {title}

    + +
    + +
    +
    + + setSearchQuery(e.target.value)} + placeholder="搜索列名..." + className="w-full h-8 pl-8 pr-3 rounded-lg bg-elevated border border-border text-xs text-foreground placeholder:text-muted focus:outline-none focus:border-accent/50 transition-colors" + /> +
    +
    + +
    + {activeCols.length > 0 && ( +
    +
    + + 已启用 + {activeCols.length} 列 · 拖拽排序 +
    + + c.id)} strategy={verticalListSortingStrategy}> + {activeCols.map(col => ( + + ))} + + +
    + )} + +
    + +
    +
    + + {builtinSectionLabel} +
    + + {filteredGroups.map(group => { + const isExpanded = expandedGroups.has(group.id) + const groupCols = group.keys + .map(k => keyToId.get(k)) + .filter((id): id is string => !!id) + .map(id => colById.get(id)) + .filter((c): c is ColumnConfig => !!c) + if (groupCols.length === 0) return null + const visCount = groupCols.filter(c => c.visible).length + + return ( +
    + + + {isExpanded && ( + +
    + {groupCols.map(col => renderBuiltinRow(col))} +
    +
    + )} +
    +
    + ) + })} +
    + + {extTables.length > 0 && ( +
    +
    + + 扩展数据列 +
    +
    + {extTables.map(table => { + const isExpanded = expandedTables.has(table.id) + const dataFields = table.columns + .filter(c => !['symbol', 'code', 'date'].includes(c.name)) + .filter(c => extFieldFilter ? extFieldFilter(c) : true) + const activeCount = dataFields.filter(f => { + const colId = `ext:${table.id}:${f.name}` + return columns.some(c => c.id === colId && c.visible) + }).length + return ( +
    + + + {isExpanded && ( + +
    + {dataFields.map(field => renderExtFieldRow(table.id, field))} +
    +
    + )} +
    +
    + ) + })} +
    +
    + )} + + {extTables.length === 0 && extSchema.isSuccess && ( +
    + 暂无扩展数据表,可在「数据」页面创建 +
    + )} +
    + +
    + )} + + ) +} diff --git a/frontend/src/components/Logo.tsx b/frontend/src/components/Logo.tsx new file mode 100644 index 0000000..e178590 --- /dev/null +++ b/frontend/src/components/Logo.tsx @@ -0,0 +1,59 @@ +// 原创 logo:方括号 [ ] 包裹一根带 wick 的 K 线 +// +// 概念: +// - 外层 brackets:终端 / 代码 / 引用边界 — 赛博 + quant 气质 +// - 中央 wick+body:一根标准 K 线 — 直接的金融指代 +// - body 在垂直中线偏下:体重感,bullish 暗示(上影长 > 下影) +// +// 用 currentColor,继承父级 color 设定,方便切换品牌色。 +interface LogoProps { + className?: string + size?: number + style?: React.CSSProperties +} + +export function Logo({ className, size = 32, style }: LogoProps) { + return ( + + {/* 左方括号 */} + + {/* 右方括号 */} + + {/* K 线 wick(上下影线,半透明) */} + + {/* K 线 body — 偏下,意味"上影长 / 反弹站住" */} + + + ) +} diff --git a/frontend/src/components/PageHeader.tsx b/frontend/src/components/PageHeader.tsx new file mode 100644 index 0000000..17d849e --- /dev/null +++ b/frontend/src/components/PageHeader.tsx @@ -0,0 +1,25 @@ +import { cn } from '@/lib/cn' + +interface Props { + title: string + subtitle?: string + right?: React.ReactNode + className?: string +} + +export function PageHeader({ title, subtitle, right, className }: Props) { + return ( +
    +
    +

    {title}

    + {subtitle && {subtitle}} +
    + {right} +
    + ) +} diff --git a/frontend/src/components/StockDailyKChart.tsx b/frontend/src/components/StockDailyKChart.tsx new file mode 100644 index 0000000..0182727 --- /dev/null +++ b/frontend/src/components/StockDailyKChart.tsx @@ -0,0 +1,232 @@ +import { useCallback, useEffect, useMemo, useState } from 'react' +import { useQuery } from '@tanstack/react-query' +import { api, type KlineRow } from '@/lib/api' +import { QK } from '@/lib/queryKeys' +import { + EChartsCandlestick, + OVERLAY_INDICATORS, + SUB_CHARTS, + type ChartMarker, + type ChartPriceLine, + type ChartRange, + type OHLC, + type StockInfo, +} from '@/components/EChartsCandlestick' + +const SUB_INFO_H = 16 +const SUB_GAP = 4 +const MAX_DAYS = 2000 + +export interface StockDailyKChartResult { + rows: OHLC[] + rawRows: KlineRow[] + stockInfo?: StockInfo + name?: string +} + +interface Props { + symbol: string + height?: number + className?: string + dateRange?: { start: string; end: string } + markers?: ChartMarker[] + ranges?: ChartRange[] + priceLines?: ChartPriceLine[] + showLimitMarkers?: boolean + showIndicatorControls?: boolean + showMarkerToggle?: boolean + showMA?: boolean + showInfoBar?: boolean + visibleBars?: number + linkedPrice?: number | null + onDateClick?: (date: string) => void + onDataChange?: (result: StockDailyKChartResult) => void +} + +function isValidRow(r: any): boolean { + return r && r.date != null && r.open != null && r.close != null +} + +export function toOHLC(rows: KlineRow[]): OHLC[] { + return rows + .filter(isValidRow) + .map(r => ({ + date: typeof r.date === 'string' ? r.date.slice(0, 10) : String(r.date), + open: Number(r.open), + high: Number(r.high), + low: Number(r.low), + close: Number(r.close), + volume: Number(r.volume ?? 0), + ma5: r.ma5 != null ? Number(r.ma5) : null, + ma10: r.ma10 != null ? Number(r.ma10) : null, + ma20: r.ma20 != null ? Number(r.ma20) : null, + ma60: r.ma60 != null ? Number(r.ma60) : null, + macd_dif: r.macd_dif != null ? Number(r.macd_dif) : null, + macd_dea: r.macd_dea != null ? Number(r.macd_dea) : null, + macd_hist: r.macd_hist != null ? Number(r.macd_hist) : null, + rsi_6: r.rsi_6 != null ? Number(r.rsi_6) : null, + rsi_14: r.rsi_14 != null ? Number(r.rsi_14) : null, + rsi_24: r.rsi_24 != null ? Number(r.rsi_24) : null, + kdj_k: r.kdj_k != null ? Number(r.kdj_k) : null, + kdj_d: r.kdj_d != null ? Number(r.kdj_d) : null, + kdj_j: r.kdj_j != null ? Number(r.kdj_j) : null, + boll_upper: r.boll_upper != null ? Number(r.boll_upper) : null, + boll_lower: r.boll_lower != null ? Number(r.boll_lower) : null, + })) +} + +function buildLimitUpMarkers(rows: KlineRow[]): ChartMarker[] { + const markers: ChartMarker[] = [] + for (const r of rows) { + const date = typeof r.date === 'string' ? r.date.slice(0, 10) : String(r.date) + if (r.signal_broken_limit_up) { + markers.push({ date, kind: 'neutral', above: true, color: '#8B5CF6', label: '炸' }) + } else if (r.signal_limit_up) { + const boards: number = r.consecutive_limit_ups ?? 1 + markers.push({ date, kind: 'buy', above: true, color: '#FACC15', label: boards <= 1 ? '板' : String(boards) }) + } + } + return markers +} + +export function getDefaultRange(): { start: string; end: string } { + const now = new Date() + const end = now.toISOString().slice(0, 10) + const s = new Date(now) + s.setMonth(s.getMonth() - 6) + const start = s.toISOString().slice(0, 10) + return { start, end } +} + +function rangeDays(range: { start: string; end: string }): number { + const start = new Date(range.start) + const end = new Date(range.end) + return Math.min(Math.ceil((end.getTime() - start.getTime()) / 86400000) + 30, MAX_DAYS) +} + +export function StockDailyKChart({ + symbol, + height = 520, + className, + dateRange: externalDateRange, + markers, + ranges, + priceLines, + showLimitMarkers = true, + showIndicatorControls = true, + showMarkerToggle = true, + showMA = true, + showInfoBar = true, + visibleBars = 60, + linkedPrice, + onDateClick, + onDataChange, +}: Props) { + const [activeIndicators, setActiveIndicators] = useState(['vol']) + const [showMarkers, setShowMarkers] = useState(true) + const dateRange = externalDateRange ?? getDefaultRange() + const days = useMemo(() => rangeDays(dateRange), [dateRange]) + + const kline = useQuery({ + queryKey: QK.kline(symbol, dateRange.start, dateRange.end), + queryFn: () => api.klineDaily(symbol, days, dateRange), + enabled: !!symbol, + placeholderData: (prev) => prev, + }) + + const rows = useMemo(() => toOHLC(kline.data?.rows ?? []), [kline.data?.rows]) + const stockInfo = kline.data?.stock_info + const limitMarkers = useMemo(() => buildLimitUpMarkers(kline.data?.rows ?? []), [kline.data?.rows]) + const allMarkers = useMemo(() => [ + ...(markers ?? []), + ...(showLimitMarkers ? limitMarkers : []), + ], [limitMarkers, markers, showLimitMarkers]) + + const toggleIndicator = useCallback((key: string) => { + setActiveIndicators(prev => prev.includes(key) ? prev.filter(k => k !== key) : [...prev, key]) + }, []) + + const activeSubDefs = activeIndicators + .map(key => SUB_CHARTS.find(s => s.key === key)) + .filter((d): d is typeof SUB_CHARTS[number] => !!d) + let subExtraH = 0 + activeSubDefs.forEach(def => { subExtraH += SUB_INFO_H + def.height }) + if (activeSubDefs.length > 0) subExtraH += activeSubDefs.length * SUB_GAP + 14 + const chartHeight = height + subExtraH + + useEffect(() => { + onDataChange?.({ rows, rawRows: kline.data?.rows ?? [], stockInfo, name: kline.data?.name }) + }, [kline.data?.name, kline.data?.rows, onDataChange, rows, stockInfo]) + + if (!symbol) return null + + return ( +
    + {showIndicatorControls && rows.length > 0 && ( +
    + {SUB_CHARTS.map(ind => ( + + ))} + {OVERLAY_INDICATORS.map(ind => ( + + ))} + {showMarkerToggle && showLimitMarkers && ( + + )} +
    + )} + {kline.isLoading &&
    加载中…
    } + {kline.isError &&
    日K加载失败
    } + {!kline.isLoading && !kline.isError && (kline.data?.rows?.length ?? 0) > 0 && rows.length === 0 && ( +
    数据格式异常,请刷新页面
    + )} + {rows.length > 0 && ( + + )} +
    + ) +} diff --git a/frontend/src/components/StockInfoBar.tsx b/frontend/src/components/StockInfoBar.tsx new file mode 100644 index 0000000..77cfbad --- /dev/null +++ b/frontend/src/components/StockInfoBar.tsx @@ -0,0 +1,66 @@ +import type { KlineRow } from '@/lib/api' +import { fmtPrice, fmtBigNum } from '@/lib/format' + +const BULL = '#C74040' +const BEAR = '#2D9B65' + +interface Props { + symbol: string + name?: string + stockInfo?: { name?: string; total_shares?: number; float_shares?: number } + rows: KlineRow[] +} + +export function StockInfoBar({ symbol, name, stockInfo, rows }: Props) { + if (rows.length === 0) return null + + const latest = rows[rows.length - 1] + const prev = rows.length >= 2 ? rows[rows.length - 2] : null + const close = Number(latest.close) + const chg = prev ? close - Number(prev.close) : 0 + const chgPct = prev ? chg / Number(prev.close) * 100 : 0 + const isUp = chg >= 0 + const clr = isUp ? BULL : BEAR + + const totalShares = stockInfo?.total_shares + const floatShares = stockInfo?.float_shares + const marketCap = totalShares ? close * totalShares : null + const floatMarketCap = floatShares ? close * floatShares : null + const turnoverRate = floatShares && latest.volume + ? (Number(latest.volume) * 100 / floatShares * 100) + : null + + const displayName = stockInfo?.name ?? name ?? '' + + return ( +
    + {/* Row 1: code, name, price, change, change% */} +
    + {symbol} + {displayName} + + {fmtPrice(close)} + + + {isUp ? '+' : ''}{fmtPrice(chg)} + + + {isUp ? '+' : ''}{fmtPrice(chgPct)}% + +
    + + {/* Row 2: market cap, float market cap, turnover rate */} +
    + {marketCap != null && ( + 市值 {fmtBigNum(marketCap)} + )} + {floatMarketCap != null && ( + 流通值 {fmtBigNum(floatMarketCap)} + )} + {turnoverRate != null && ( + 换手 {turnoverRate.toFixed(2)}% + )} +
    +
    + ) +} diff --git a/frontend/src/components/StockIntradayChart.tsx b/frontend/src/components/StockIntradayChart.tsx new file mode 100644 index 0000000..e4fbb0a --- /dev/null +++ b/frontend/src/components/StockIntradayChart.tsx @@ -0,0 +1,120 @@ +import { useEffect, useMemo, useState } from 'react' +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' +import { Loader2 } from 'lucide-react' +import { api, type MinuteKlineRow } from '@/lib/api' +import { QK } from '@/lib/queryKeys' +import { EChartsIntraday } from '@/components/EChartsIntraday' + +interface Props { + symbol: string + date: string | null + height?: number + prevClose?: number + className?: string + onPriceHover?: (price: number | null) => void +} + +export function StockIntradayChart({ + symbol, + date, + height = 520, + prevClose, + className, + onPriceHover, +}: Props) { + const qc = useQueryClient() + const [minuteDismissed, setMinuteDismissed] = useState(false) + + const minute = useQuery({ + queryKey: QK.klineMinute(symbol, date ?? ''), + queryFn: () => api.klineMinute(symbol, date ?? undefined), + enabled: !!symbol && !!date, + }) + + const fetchMinute = useMutation({ + mutationFn: () => api.extendMinuteHistory(5, 'day'), + onSuccess: () => { + qc.invalidateQueries({ queryKey: ['kline-minute', symbol] }) + qc.invalidateQueries({ queryKey: QK.dataStatus }) + qc.invalidateQueries({ queryKey: QK.pipelineJobs }) + setMinuteDismissed(false) + }, + }) + + const minuteRows: MinuteKlineRow[] = useMemo(() => minute.data?.rows ?? [], [minute.data?.rows]) + // source=none 表示本地无数据且 TickFlow 也拉不到 (停牌/复牌延迟/非交易日) + // 此时不弹"是否获取"询问窗, 只做静态提示, 避免误导用户去拉明知拉不到的数据 + const sourceIsNone = minute.data?.source === 'none' + + useEffect(() => { + setMinuteDismissed(false) + onPriceHover?.(null) + }, [date, onPriceHover]) + + if (!symbol || !date) return null + + return ( +
    + {minute.isLoading &&
    分时加载中…
    } + {!minute.isLoading && minuteRows.length === 0 && ( + <> + {fetchMinute.isPending ? ( +
    + + 正在获取最近5日分钟K… +
    + ) : sourceIsNone ? ( + // 数据源确认无此日分钟数据 (停牌/复牌延迟等): 静态提示 + 保留重试 +
    +
    该日暂无分钟数据(数据源未提供)
    + +
    + ) : minuteDismissed ? ( +
    +
    暂无分钟数据
    + +
    + ) : ( +
    +
    是否立即获取最近5日分钟K?
    +
    + + +
    +
    + )} + + )} + {minuteRows.length > 0 && ( + + )} +
    + ) +} diff --git a/frontend/src/components/StockPanel.tsx b/frontend/src/components/StockPanel.tsx new file mode 100644 index 0000000..1568fb1 --- /dev/null +++ b/frontend/src/components/StockPanel.tsx @@ -0,0 +1,115 @@ +import { useEffect, useState, useCallback } from 'react' +import { type KlineRow } from '@/lib/api' +import { StockInfoBar } from '@/components/StockInfoBar' +import { StockDailyKChart, getDefaultRange, type StockDailyKChartResult } from '@/components/StockDailyKChart' +import { StockIntradayChart } from '@/components/StockIntradayChart' +import type { ChartMarker, ChartPriceLine, ChartRange } from '@/components/EChartsCandlestick' + +interface Props { + symbol: string + height?: number + showIntraday?: boolean + className?: string + /** 当用户点击蜡烛选中日期时回调(用于外部自动开启分时图)。 */ + onSelectDate?: (date: string) => void + /** 外部传入的日期范围 */ + dateRange?: { start: string; end: string } + markers?: ChartMarker[] + ranges?: ChartRange[] + priceLines?: ChartPriceLine[] + showLimitMarkers?: boolean + showMarkerToggle?: boolean +} + +export { getDefaultRange } + +export function StockPanel({ + symbol, + height = 520, + showIntraday = true, + className, + onSelectDate, + dateRange: externalDateRange, + markers, + ranges, + priceLines, + showLimitMarkers = true, + showMarkerToggle = true, +}: Props) { + const [linkedPrice, setLinkedPrice] = useState(null) + const [selectedDate, setSelectedDate] = useState(null) + const [dailyResult, setDailyResult] = useState(null) + + const dateRange = externalDateRange ?? getDefaultRange() + + const handleDateClick = useCallback((date: string) => { + setSelectedDate(date) + onSelectDate?.(date) + }, [onSelectDate]) + + const rows = dailyResult?.rows ?? [] + const stockInfo = dailyResult?.stockInfo + const rawRows: KlineRow[] = dailyResult?.rawRows ?? [] + + // symbol 变化时重置分时相关状态,避免切股后残留旧日期 + useEffect(() => { + setSelectedDate(null) + setLinkedPrice(null) + setDailyResult(null) + }, [symbol]) + + // 当分时开启、无选中日期时,自动选中最新日期 + useEffect(() => { + if (showIntraday && !selectedDate && rows.length > 0) { + setSelectedDate(rows[rows.length - 1].date) + } + }, [showIntraday, selectedDate, rows]) + + const selectedIdx = selectedDate ? rows.findIndex(r => r.date === selectedDate) : -1 + const prevClose = selectedIdx > 0 + ? rows[selectedIdx - 1].close + : rows.length >= 2 + ? rows[rows.length - 2].close + : undefined + if (!symbol) return null + + return ( +
    + + +
    + + + {showIntraday && selectedDate && ( + + )} +
    +
    + ) +} diff --git a/frontend/src/components/StockPreviewDialog.tsx b/frontend/src/components/StockPreviewDialog.tsx new file mode 100644 index 0000000..5b39291 --- /dev/null +++ b/frontend/src/components/StockPreviewDialog.tsx @@ -0,0 +1,212 @@ +import { useState, useEffect } from 'react' +import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' +import { motion, AnimatePresence } from 'framer-motion' +import { X, RefreshCw, Clock, Star } from 'lucide-react' +import { api } from '@/lib/api' +import { QK } from '@/lib/queryKeys' +import { StockPanel, getDefaultRange } from '@/components/StockPanel' +import { DatePicker } from '@/components/DatePicker' + +interface Props { + symbol: string | null + name?: string + onClose: () => void +} + +// ===== 板块标识(与 Screener 列表一致)===== + +// 预设快捷范围(只保留半年和1年) +const PRESETS: { label: string; months: number }[] = [ + { label: '半年', months: 6 }, + { label: '1年', months: 12 }, +] + +function boardTag(symbol: string): { label: string; color: string } | null { + if (/^(300|301)/.test(symbol)) return { label: '创', color: 'text-[#f97316] bg-[#f97316]/12 border-[#f97316]/25' } + if (/^688/.test(symbol)) return { label: '科', color: 'text-purple-400 bg-purple-400/12 border-purple-400/25' } + if (/^[48]/.test(symbol)) return { label: '北', color: 'text-cyan-400 bg-cyan-400/12 border-cyan-400/25' } + return null +} + +export function StockPreviewDialog({ symbol, name, onClose }: Props) { + const [showIntraday, setShowIntraday] = useState(false) + const [dateRange, setDateRange] = useState(getDefaultRange) + const qc = useQueryClient() + + const watchlist = useQuery({ + queryKey: QK.watchlist, + queryFn: api.watchlistList, + enabled: !!symbol, + }) + const inWatchlist = (watchlist.data?.symbols ?? []).some((s: any) => s.symbol === symbol) + + const toggleWatchlist = useMutation({ + mutationFn: () => inWatchlist ? api.watchlistRemove(symbol!) : api.watchlistAdd(symbol!), + onSuccess: () => { + qc.invalidateQueries({ queryKey: QK.watchlist }) + qc.invalidateQueries({ queryKey: QK.watchlistEnriched() }) + }, + }) + + // ESC 关闭 + useEffect(() => { + if (!symbol) return + const handler = (e: KeyboardEvent) => { + if (e.key === 'Escape') onClose() + } + document.addEventListener('keydown', handler) + return () => document.removeEventListener('keydown', handler) + }, [symbol, onClose]) + + const handleRefresh = () => { + if (!symbol) return + qc.invalidateQueries({ queryKey: ['kline', symbol!] }) + if (showIntraday) { + qc.invalidateQueries({ queryKey: ['kline-minute', symbol!] }) + } + } + + return ( + + {symbol && ( +
    + {/* 遮罩 */} + + + {/* 弹窗主体 */} + + {/* 顶栏 */} +
    +
    + {(() => { + const board = symbol ? boardTag(symbol) : null + return board ? ( + + {board.label} + + ) : null + })()} + {symbol} + {name && {name}} +
    + +
    + {/* 日期范围快捷 */} + {PRESETS.map(p => { + const now = new Date() + const s = new Date(now) + s.setMonth(s.getMonth() - p.months) + const expected = s.toISOString().slice(0, 10) + const isActive = dateRange.start === expected + return ( + + ) + })} + setDateRange(prev => ({ ...prev, start: v }))} + max={dateRange.end} + /> + ~ + setDateRange(prev => ({ ...prev, end: v }))} + min={dateRange.start} + /> + + | + + {/* 分时开关 */} + + + | + + {/* 加自选 */} + + + | + + {/* 刷新 */} + + + {/* 关闭 */} + +
    +
    + + {/* K 线内容 */} +
    + { if (!showIntraday) setShowIntraday(true) }} + dateRange={dateRange} + /> +
    +
    +
    + )} +
    + ) +} diff --git a/frontend/src/components/Toast.tsx b/frontend/src/components/Toast.tsx new file mode 100644 index 0000000..389514d --- /dev/null +++ b/frontend/src/components/Toast.tsx @@ -0,0 +1,49 @@ +import { useCallback, useEffect, useState } from 'react' + +// ===== 全局 toast 状态 ===== +type ToastItem = { id: number; msg: string; kind: 'error' | 'success' } +let _id = 0 +const _listeners: Set<(items: ToastItem[]) => void> = new Set() +let _queue: ToastItem[] = [] + +function _emit() { _listeners.forEach(fn => fn([..._queue])) } + +function toast(msg: string, kind: 'error' | 'success' = 'error') { + const item = { id: ++_id, msg, kind } + _queue = [..._queue, item] + _emit() + setTimeout(() => { _queue = _queue.filter(t => t.id !== item.id); _emit() }, 4000) +} + +export { toast } + +// ===== Toast 容器 — 挂在 Layout 最顶层 ===== +export function ToastContainer() { + const [items, setItems] = useState([]) + + const sub = useCallback(() => { + _listeners.add(setItems) + return () => { _listeners.delete(setItems) } + }, []) + + useEffect(sub, [sub]) + + if (!items.length) return null + + return ( +
    + {items.map(t => ( +
    + {t.msg} +
    + ))} +
    + ) +} diff --git a/frontend/src/components/analysis-shared.tsx b/frontend/src/components/analysis-shared.tsx new file mode 100644 index 0000000..5a1ad33 --- /dev/null +++ b/frontend/src/components/analysis-shared.tsx @@ -0,0 +1,451 @@ +/** + * 概念/行业分析 — 共享 UI 组件 + * + * 包含: + * - AnalysisConfigDialog: 字段配置弹窗 + * - DimensionHeatmap: 维度热力图块 + * - OverviewStatCards: 总览统计卡片 + * - DimensionGroupSidebar: 维度分组侧边栏 + */ + +import { useMemo, useState } from 'react' +import { useQuery } from '@tanstack/react-query' +import { motion } from 'framer-motion' +import { + BarChart3, + ChevronDown, + Database, + Search, + Settings2, + Tags, + TrendingUp, + X, +} from 'lucide-react' +import { api, type ExtDataField } from '@/lib/api' +import { QK } from '@/lib/queryKeys' +import { cn } from '@/lib/cn' +import type { DimensionGroup, QuoteMap } from '@/lib/analysis-adapter' +import { computeQuoteMetrics } from '@/lib/analysis-adapter' +import { fmtPct, priceColorClass } from '@/lib/format' + +// ===== 配置类型 ===== + +export interface AnalysisFieldConfig { + /** 选中的扩展数据源 ID */ + configId?: string + /** 手动指定的维度字段(覆盖自动探测) */ + dimensionField?: string + /** 层级字段统计级别(如行业 1/2/3 级) */ + hierarchyLevel?: 1 | 2 | 3 +} + +export interface SchemaOption { + id: string + label: string + columns: { name: string; type: string; label: string }[] +} + +// ===== 配置弹窗 ===== + +export function AnalysisConfigDialog({ + currentConfig, + onSave, + onClose, + showHierarchyLevel = false, +}: { + currentConfig: AnalysisFieldConfig + onSave: (config: AnalysisFieldConfig) => void + onClose: () => void + showHierarchyLevel?: boolean +}) { + const [draft, setDraft] = useState(currentConfig) + const { data: extList } = useQuery({ + queryKey: QK.extData, + queryFn: api.extDataList, + }) + const { data: schemaData } = useQuery({ + queryKey: QK.extDataSchemaAll, + queryFn: api.extDataSchemaAll, + }) + + const configs = extList?.items ?? [] + + const fieldsForConfig = useMemo((): ExtDataField[] => { + if (!draft.configId || !schemaData?.items) return [] + const schema = schemaData.items.find(s => s.id === draft.configId) + return schema?.columns.map(c => ({ name: c.name, dtype: c.type, label: c.label })) ?? [] + }, [draft.configId, schemaData]) + + const nonMetaFields = fieldsForConfig.filter( + f => !['symbol', 'code', 'date', 'name'].includes(f.name), + ) + + return ( +
    + e.stopPropagation()} + > +
    + 配置数据源 + +
    + +
    + {/* 数据源选择 */} +
    + 扩展数据源 + +
    + + {/* 维度字段选择 */} + {nonMetaFields.length > 0 && ( +
    + 维度字段(留空自动探测) + +
    + )} + + {showHierarchyLevel && ( +
    + 统计层级 + +
    + )} + +
    + 系统自动检测数据结构:支持"个股→概念/行业"和"概念/行业→成分股列表"两种模式。 + {showHierarchyLevel ? ' 行业字段按 “-” 拆分为 1/2/3 级。' : ''} +
    +
    + +
    + + +
    +
    +
    + ) +} + +// ===== 总览统计卡片 ===== + +export function OverviewStatCards({ + groups, + totalStocks, + configLabel, + dateStr, + accentColor, +}: { + groups: DimensionGroup[] + totalStocks: number + configLabel: string + dateStr?: string | null + accentColor: string +}) { + const cards = [ + { label: '数据源', value: configLabel, hint: dateStr ?? '快照', icon: Database }, + { label: '维度数量', value: groups.length, hint: '按维度聚合分组', icon: Tags }, + { label: '覆盖标的', value: totalStocks, hint: '去重股票数', icon: BarChart3 }, + { + label: '最大分组', + value: groups[0]?.key ?? '—', + hint: groups[0] ? `${groups[0].count} 只` : '', + icon: TrendingUp, + }, + ] + + return ( +
    + {cards.map(card => ( +
    +
    + {card.label} + +
    +
    + {card.value} +
    +
    {card.hint}
    +
    + ))} +
    + ) +} + +// ===== 维度热力图 ===== + +export function DimensionHeatmap({ + groups, + quoteMap, + selectedKey, + onSelect, + colorScheme, +}: { + groups: DimensionGroup[] + quoteMap: Map + selectedKey: string | null + onSelect: (key: string | null) => void + colorScheme: 'blue' | 'amber' +}) { + const [showAll, setShowAll] = useState(false) + // 收起时最大高度(约 3 行标签高度) + const collapsedMaxH = '8rem' + + const enriched = useMemo(() => { + return groups.map(g => { + const qm = computeQuoteMetrics(g.stocks, quoteMap) + return { ...g, quoteMetrics: qm } + }) + }, [groups, quoteMap]) + + // 根据涨跌比渲染颜色强度 + const colors = colorScheme === 'blue' + ? { up: [59, 130, 246], down: [96, 165, 250], bg: [30, 64, 175] } + : { up: [245, 158, 11], down: [251, 191, 36], bg: [180, 83, 9] } + + return ( +
    +
    + 热度分布(按标的覆盖数) + +
    +
    + {enriched.map(g => { + const qm = g.quoteMetrics + const total = qm.upCount + qm.downCount + qm.flatCount + const upRatio = total > 0 ? qm.upCount / total : 0.5 + const size = Math.max(0.6, Math.min(1.4, g.count / (enriched[0]?.count || 1))) + const active = selectedKey === g.key + const [r, gr, b] = colors.up + + return ( + + ) + })} +
    +
    + ) +} + +// ===== 维度分组侧边栏 ===== + +export function DimensionGroupSidebar({ + groups, + quoteMap, + selectedKey, + onSelect, + searchValue, + onSearchChange, + kindLabel, + colorScheme, +}: { + groups: DimensionGroup[] + quoteMap: Map + selectedKey: string | null + onSelect: (key: string) => void + searchValue: string + onSearchChange: (v: string) => void + kindLabel: string + colorScheme: 'blue' | 'amber' +}) { + const q = searchValue.trim().toLowerCase() + const filtered = q + ? groups.filter(g => g.key.toLowerCase().includes(q)) + : groups + + const accentColor = colorScheme === 'blue' ? 'rgba(59,130,246,0.7)' : 'rgba(245,158,11,0.7)' + const accentBg = colorScheme === 'blue' ? 'rgba(59,130,246,0.1)' : 'rgba(245,158,11,0.1)' + const accentBorder = colorScheme === 'blue' ? 'rgba(59,130,246,0.25)' : 'rgba(245,158,11,0.25)' + + return ( +
    +
    +

    {kindLabel}榜单

    +

    按覆盖标的数量排序

    +
    +
    +
    + + onSearchChange(e.target.value)} + placeholder={`搜索${kindLabel}`} + className="h-8 w-full rounded-btn border border-border bg-base pl-8 pr-3 text-xs text-foreground placeholder:text-muted/50 focus:outline-none focus:border-accent/50" + /> +
    +
    +
    + {filtered.length === 0 ? ( +
    没有可展示的分组
    + ) : filtered.slice(0, 200).map((group, i) => { + const active = selectedKey === group.key + const qm = computeQuoteMetrics(group.stocks, quoteMap) + return ( + + ) + })} +
    +
    + ) +} + +// ===== 行情摘要条 ===== + +export function QuoteSummaryBar({ + groups, + quoteMap, +}: { + groups: DimensionGroup[] + quoteMap: Map +}) { + const stats = useMemo(() => { + let upTotal = 0, downTotal = 0, flatTotal = 0 + for (const g of groups) { + const qm = computeQuoteMetrics(g.stocks, quoteMap) + upTotal += qm.upCount + downTotal += qm.downCount + flatTotal += qm.flatCount + } + return { upTotal, downTotal, flatTotal } + }, [groups, quoteMap]) + + const total = stats.upTotal + stats.downTotal + stats.flatTotal + if (total === 0) return null + + const upPct = (stats.upTotal / total) * 100 + const downPct = (stats.downTotal / total) * 100 + + return ( +
    +
    +
    +
    +
    +
    + {stats.upTotal}涨 + / + {stats.downTotal}跌 +
    + ) +} + +// ===== 配置按钮 ===== + +export function ConfigButton({ onClick }: { onClick: () => void }) { + return ( + + ) +} diff --git a/frontend/src/components/data/ActiveJobCard.tsx b/frontend/src/components/data/ActiveJobCard.tsx new file mode 100644 index 0000000..025227a --- /dev/null +++ b/frontend/src/components/data/ActiveJobCard.tsx @@ -0,0 +1,135 @@ +import { useRef, useMemo, useEffect } from 'react' +import { motion } from 'framer-motion' +import { Loader2, CheckCircle2, XCircle } from 'lucide-react' +import { formatDuration, formatLogTime } from '@/lib/format' +import { Pill } from './StatCard' +import type { PipelineJob } from '@/lib/api' + +export const STAGE_LABELS: Record = { + init: '初始化', + resolve_universe: '解析标的池', + sync_instruments: '同步标的维表', + sync_daily: '同步日 K', + sync_adj: '同步除权因子', + compute_enriched: '计算技术指标', + sync_minute: '同步分钟 K', + extend_history: '扩展日K历史', + extend_minute: '扩展分钟K历史', + rebuild_enriched: '全量计算', + refresh_views: '刷新视图', + done: '完成', +} + +function LogViewer({ log }: { log: PipelineJob['log'] }) { + const containerRef = useRef(null) + + const displayLog = useMemo(() => { + if (!log.length) return [] + return log.filter((line, i) => { + const next = log[i + 1] + if ( + next && + line.stage === next.stage && + /\d+\/\d+/.test(line.msg) && + /\d+\/\d+/.test(next.msg) + ) { + return false + } + return true + }) + }, [log]) + + useEffect(() => { + const el = containerRef.current + if (el) el.scrollTop = el.scrollHeight + }, [displayLog]) + + return ( +
    + {displayLog.map((line, i) => ( +
    + {formatLogTime(line.ts)} + [{STAGE_LABELS[line.stage] ?? line.stage}] + {line.msg} +
    + ))} + {displayLog.length === 0 &&
    等待启动…
    } +
    + ) +} + +export function ActiveJobCard({ job }: { job: PipelineJob }) { + const statusMap = { + running: { icon: Loader2, color: 'text-accent', label: '运行中', spinning: true, border: 'border-accent/40', bg: 'bg-accent/5' }, + pending: { icon: Loader2, color: 'text-muted', label: '排队中', spinning: true, border: 'border-border', bg: 'bg-surface' }, + succeeded: { icon: CheckCircle2, color: 'text-bear', label: '完成', spinning: false, border: 'border-bear/30', bg: 'bg-bear/5' }, + failed: { icon: XCircle, color: 'text-danger', label: '失败', spinning: false, border: 'border-danger/40', bg: 'bg-danger/5' }, + } as const + const meta = statusMap[job.status] + const Icon = meta.icon + const isDone = job.status === 'succeeded' || job.status === 'failed' + const stageLabel = isDone ? meta.label : (STAGE_LABELS[job.stage] ?? job.stage) + + return ( +
    +
    +
    + +
    +
    + {meta.label}{!isDone && ` · ${stageLabel}`} +
    +
    + {job.id} · {job.duration_s != null ? formatDuration(job.duration_s) : '进行中'} +
    +
    +
    + {!isDone && ( +
    + {job.progress}% +
    + )} +
    + + {!isDone && ( +
    +
    + +
    + {job.stage_pct > 0 && ( +
    + 当前阶段 + {job.stage_pct}% +
    + )} +
    + )} + + + + {job.status === 'succeeded' && job.result && (() => { + const skipped = new Set(job.result.skipped_stages ?? []) + const cell = (stage: string | null, v: string) => + stage && skipped.has(stage) ? '跳过' : v + return ( +
    + + + + + +
    + ) + })()} + {job.status === 'failed' && job.error && ( +
    + {job.error} +
    + )} +
    + ) +} diff --git a/frontend/src/components/data/EnrichedRebuildPanel.tsx b/frontend/src/components/data/EnrichedRebuildPanel.tsx new file mode 100644 index 0000000..b50cfdc --- /dev/null +++ b/frontend/src/components/data/EnrichedRebuildPanel.tsx @@ -0,0 +1,111 @@ +import { useState } from 'react' +import { useMutation, useQueryClient } from '@tanstack/react-query' +import { Loader2 } from 'lucide-react' +import { api } from '@/lib/api' +import { QK } from '@/lib/queryKeys' +import { usePreferences } from '@/lib/useSharedQueries' + +export function EnrichedRebuildPanel({ isRunning, onStart }: { isRunning: boolean; onStart: () => void }) { + const qc = useQueryClient() + const prefs = usePreferences() + const batchSize = prefs.data?.enriched_batch_size ?? 1000 + const [editing, setEditing] = useState(false) + const [draftSize, setDraftSize] = useState(String(batchSize)) + const [hint, setHint] = useState(null) + + function clampAndSave(raw: number) { + if (isNaN(raw) || 1 > raw) { setHint('已自动设为最小值 1'); saveBatch.mutate(1); return } + if (raw > 10000) { setHint('已自动设为上限 10000'); saveBatch.mutate(10000); return } + setHint(null); saveBatch.mutate(raw) + } + + const saveBatch = useMutation({ + mutationFn: (size: number) => api.updateEnrichedBatchSize(size), + onSuccess: () => { + qc.invalidateQueries({ queryKey: QK.preferences }) + setEditing(false) + }, + }) + const rebuild = useMutation({ + mutationFn: api.rebuildEnriched, + onSuccess: () => { + onStart() + qc.invalidateQueries({ queryKey: QK.pipelineJobs }) + }, + }) + + return ( +
    +
    +
    +
    +
    批次大小
    +
    每批计算的标的数量,影响内存占用与进度粒度
    +
    + {editing ? ( +
    + setDraftSize(e.target.value)} + className="w-20 px-2 py-1 text-xs font-mono rounded-btn border border-border bg-surface text-foreground text-right tabular-nums focus:outline-none focus:border-accent" + min={1} + max={10000} + autoFocus + onKeyDown={e => { + if (e.key === 'Enter') clampAndSave(parseInt(draftSize)) + if (e.key === 'Escape') { setEditing(false); setHint(null) } + }} + /> + + +
    + ) : ( + + )} +
    +
    + + 每批内存占用 = 批次大小 × 日K历史天数。批次越大或日K历史越长,内存占用越高,可能导致程序崩溃。内存不足时请适当降低此值。 + +
    + {hint && ( +
    + {hint} +
    + )} +
    + +
    +
    基于已有 kline_daily + adj_factor 全量计算前复权 + 技术指标 + 信号
    + +
    +
    + ) +} diff --git a/frontend/src/components/data/ExtendHistoryPanel.tsx b/frontend/src/components/data/ExtendHistoryPanel.tsx new file mode 100644 index 0000000..eee7cc3 --- /dev/null +++ b/frontend/src/components/data/ExtendHistoryPanel.tsx @@ -0,0 +1,98 @@ +import { useState } from 'react' +import { useMutation, useQueryClient } from '@tanstack/react-query' +import { Loader2 } from 'lucide-react' +import { api } from '@/lib/api' +import { QK } from '@/lib/queryKeys' + +export function ExtendHistoryPanel({ caps, isRunning, earliestDate, onStart }: { + caps: { label: string; capabilities: Record } | undefined + isRunning: boolean + earliestDate: string | null + onStart: () => void +}) { + const qc = useQueryClient() + const [value, setValue] = useState(6) + const [unit, setUnit] = useState<'month' | 'year'>('month') + const hasBatchCap = !!caps?.capabilities?.['kline.daily.batch'] + + const extend = useMutation({ + mutationFn: () => api.extendHistory(value, unit), + onSuccess: () => { + onStart() + qc.invalidateQueries({ queryKey: QK.pipelineJobs }) + }, + }) + + const offsetDays = unit === 'month' ? value * 30 : value * 365 + const estimate = earliestDate + ? (() => { + const d = new Date(earliestDate) + d.setDate(d.getDate() - offsetDays) + return d.toISOString().slice(0, 10) + })() + : null + + return ( +
    +
    向前扩展历史数据
    + +
    +
    + +
    + {value} +
    + +
    + +
    + {(['month', 'year'] as const).map(u => ( + + ))} +
    +
    + + {estimate && ( +
    + 预计扩展至 {estimate} + {earliestDate && (当前最早: {earliestDate})} +
    + )} + + + + {!hasBatchCap && ( + + 需 Pro+ 权限 + + )} +
    + ) +} diff --git a/frontend/src/components/data/MinuteSyncConfig.tsx b/frontend/src/components/data/MinuteSyncConfig.tsx new file mode 100644 index 0000000..df077f0 --- /dev/null +++ b/frontend/src/components/data/MinuteSyncConfig.tsx @@ -0,0 +1,189 @@ +import { useState, useEffect } from 'react' +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' +import { Loader2 } from 'lucide-react' +import { api } from '@/lib/api' +import { QK } from '@/lib/queryKeys' + +export function MinuteSyncConfig({ caps, isRunning, onStart }: { caps: { label: string; capabilities: Record } | undefined; isRunning: boolean; onStart: () => void }) { + const qc = useQueryClient() + const prefs = useQuery({ + queryKey: QK.preferences, + queryFn: api.preferences, + }) + const update = useMutation({ + mutationFn: ({ enabled, days }: { enabled: boolean; days: number }) => + api.updateMinuteSync(enabled, days), + onSuccess: () => qc.invalidateQueries({ queryKey: QK.preferences }), + }) + + const hasMinuteCap = !!caps?.capabilities?.['kline.minute.batch'] + const enabled = prefs.data?.minute_sync_enabled ?? false + const days = prefs.data?.minute_sync_days ?? 5 + const [localDays, setLocalDays] = useState(days) + + useEffect(() => { setLocalDays(days) }, [days]) + + const handleToggle = () => { + if (!hasMinuteCap) return + update.mutate({ enabled: !enabled, days: localDays }) + } + + return ( +
    +
    +
    + + + {enabled ? '自动同步' : '已关闭'} + +
    + {!hasMinuteCap && ( + + 需 Pro+ + + )} +
    + +
    + 同步天数 +
    +
    + +
    + {localDays} +
    + +
    + +
    +
    + +
    +
    向前扩展历史数据
    + +
    + +
    + A股标的 · 原始数据存储(查询时实时复权) +
    +
    + ) +} + +function MinuteExtendControls({ hasMinuteCap, isRunning, onStart }: { hasMinuteCap: boolean; isRunning: boolean; onStart: () => void }) { + const qc = useQueryClient() + const [value, setValue] = useState(5) + const [confirmOpen, setConfirmOpen] = useState(false) + + const dataStatus = useQuery({ + queryKey: QK.dataStatus, + queryFn: api.dataStatus, + }) + const hasMinuteData = !!(dataStatus.data?.minute?.rows) + + const extend = useMutation({ + mutationFn: () => api.extendMinuteHistory(value, 'day'), + onSuccess: () => { + onStart() + qc.invalidateQueries({ queryKey: QK.pipelineJobs }) + qc.invalidateQueries({ queryKey: QK.dataStatus }) + }, + }) + + const totalDays = Math.min(value, 15) + + const handleFetch = () => { + if (!hasMinuteData) { + setConfirmOpen(true) + } else { + extend.mutate() + } + } + + return ( + <> +
    +
    + +
    + {totalDays} +
    + +
    + +
    + + + + {confirmOpen && ( +
    +
    setConfirmOpen(false)} /> +
    +
    本地暂无分钟K数据,是否立即获取最近 {totalDays} 日分钟K?
    +
    + + +
    +
    +
    + )} + + ) +} diff --git a/frontend/src/components/data/QuoteConfigCard.tsx b/frontend/src/components/data/QuoteConfigCard.tsx new file mode 100644 index 0000000..02484b7 --- /dev/null +++ b/frontend/src/components/data/QuoteConfigCard.tsx @@ -0,0 +1,165 @@ +import { useState } from 'react' +import { AnimatePresence, motion } from 'framer-motion' +import { Activity, Settings } from 'lucide-react' +import { Skeleton } from './Skeleton' + +export function QuoteConfigCard({ enabled, running, isTrading, lastFetchMs, intervalS, intervalMin, intervalMax, loading, onToggle, toggling, showIntervalEdit, onShowIntervalEdit, onIntervalChange }: { + enabled: boolean + running: boolean + isTrading: boolean + lastFetchMs: number | null + intervalS: number + intervalMin: number + intervalMax: number + loading: boolean + onToggle: (enabled: boolean) => void + toggling: boolean + showIntervalEdit: boolean + onShowIntervalEdit: () => void + onIntervalChange: (v: number) => void +}) { + const statusColor = running && isTrading + ? 'bg-accent shadow-[0_0_6px_rgba(61,214,140,0.5)]' + : enabled && running + ? 'bg-warning/60' + : 'bg-muted' + + const statusText = !enabled + ? '已关闭' + : !isTrading + ? '非交易时段' + : running + ? '行情运行中' + : '已停止' + + const lastFetchTime = lastFetchMs + ? new Date(lastFetchMs).toLocaleString('zh-CN', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' }) + : null + + return ( +
    +
    +
    + +

    实时行情

    +
    + +
    + + {loading ? ( +
    +
    +
    +
    +
    +
    + ) : ( +
    +
    + 状态 +
    + + {statusText} +
    +
    +
    + 交易时段 + {isTrading ? '交易中' : '休市'} +
    +
    +
    + 轮询间隔 + +
    + {intervalS}s +
    +
    + 最后获取 + {lastFetchTime ?? '—'} +
    +
    + )} + + + {showIntervalEdit && ( + + + + )} + +
    + ) +} + +function IntervalEditor({ min, max, value, onChange }: { + min: number; max: number; value: number; onChange: (v: number) => void +}) { + const [draft, setDraft] = useState(value) + const clamped = Math.max(min, Math.min(max, draft)) + const step = min < 1 ? 0.1 : min < 3 ? 0.5 : 1 + const presets = min <= 3 ? [3, 5, 10, 30, 60] : [5, 10, 15, 30, 60] + + return ( +
    +
    + 轮询间隔 ({min}s ~ {max}s) +
    +
    + {presets.map(p => ( + + ))} +
    +
    + { const v = parseFloat(e.target.value); setDraft(v); onChange(v) }} + className="flex-1 h-1 accent-accent cursor-pointer" + /> + + {clamped < 1 ? clamped.toFixed(1) : clamped.toFixed(0)}s + +
    +
    + ) +} diff --git a/frontend/src/components/data/ScheduleEditor.tsx b/frontend/src/components/data/ScheduleEditor.tsx new file mode 100644 index 0000000..e8c2171 --- /dev/null +++ b/frontend/src/components/data/ScheduleEditor.tsx @@ -0,0 +1,43 @@ +import { useState, useEffect } from 'react' + +export function ScheduleEditor({ value, onSave, loading, hint }: { + value: { hour: number; minute: number } + onSave: (hour: number, minute: number) => void + loading: boolean + hint?: string +}) { + const [h, setH] = useState(value.hour) + const [m, setM] = useState(value.minute) + + useEffect(() => { setH(value.hour); setM(value.minute) }, [value.hour, value.minute]) + + const handleSave = () => { + if (h === value.hour && m === value.minute) return + onSave(h, m) + } + + return ( +
    + 每日 + setH(Math.max(0, Math.min(23, Number(e.target.value))))} + className="w-12 px-1.5 py-1 rounded-btn bg-base border border-border text-xs font-mono text-foreground text-center" + /> + : + setM(Math.max(0, Math.min(59, Number(e.target.value))))} + className="w-12 px-1.5 py-1 rounded-btn bg-base border border-border text-xs font-mono text-foreground text-center" + /> + + 工作日自动执行{hint ? ` · ${hint}` : ''} +
    + ) +} diff --git a/frontend/src/components/data/SchemaModal.tsx b/frontend/src/components/data/SchemaModal.tsx new file mode 100644 index 0000000..0a42867 --- /dev/null +++ b/frontend/src/components/data/SchemaModal.tsx @@ -0,0 +1,102 @@ +import { AnimatePresence, motion } from 'framer-motion' +import { useQuery } from '@tanstack/react-query' +import { api, type EnrichedField } from '@/lib/api' +import { QK } from '@/lib/queryKeys' + +const TABLE_TITLES: Record = { + instruments: '标的维表', + daily: '日 K', + adj_factor: '除权因子', + enriched: 'Enriched', + minute: '分钟 K', + index_instruments: '指数维表', + index_daily: '指数日 K', + index_enriched: '指数 Enriched', +} + +function categorize(name: string): string { + if (['symbol', 'date'].includes(name)) return '基础' + if (['open', 'high', 'low', 'close', 'volume', 'amount'].includes(name)) return '行情' + if (name.startsWith('raw_') || name.startsWith('ex_') || name === 'close_pre_adj') return '复权' + if (name.startsWith('ma')) return '均线 MA' + if (name.startsWith('ema')) return '指数均线 EMA' + if (name.startsWith('macd')) return 'MACD' + if (name.startsWith('boll')) return '布林带' + if (name.startsWith('kdj')) return 'KDJ' + if (name.startsWith('rsi')) return 'RSI' + if (name.startsWith('signal_') || name.startsWith('consecutive_')) return '信号' + if (['atr_14', 'vol_ratio_5d', 'vol_ma5', 'vol_ma10', 'momentum_5d', 'momentum_10d', 'momentum_20d', 'momentum_30d', 'momentum_60d', 'annual_vol_20d', 'change_pct', 'change_amount', 'amplitude', 'turnover_rate'].includes(name)) return '波动/动量' + if (['high_60d', 'low_60d'].includes(name)) return '极值' + return '其他' +} + +export function EnrichedSchemaModal({ table, onClose }: { table: string | null; onClose: () => void }) { + const open = !!table + const schema = useQuery({ + queryKey: QK.tableSchema(table!), + queryFn: () => api.enrichedSchema(table!), + enabled: open, + staleTime: Infinity, + }) + + const fields = schema.data ?? [] + + const groups: Record = {} + for (const f of fields) { + const cat = categorize(f.name) + if (!groups[cat]) groups[cat] = [] + groups[cat].push(f) + } + + const title = table ? (TABLE_TITLES[table] ?? table) : '' + + return ( + + {open && ( + +
    + +
    +

    {title} 字段说明

    + {fields.length} 个字段 +
    +
    + {schema.isLoading ? ( +
    加载中…
    + ) : ( +
    + {Object.entries(groups).map(([cat, items]) => ( +
    +
    {cat}
    +
    + {items.map((f) => ( +
    + {f.name} + {f.desc} + {f.type} +
    + ))} +
    +
    + ))} +
    + )} +
    +
    + + )} + + ) +} diff --git a/frontend/src/components/data/SectionTitle.tsx b/frontend/src/components/data/SectionTitle.tsx new file mode 100644 index 0000000..3756bcb --- /dev/null +++ b/frontend/src/components/data/SectionTitle.tsx @@ -0,0 +1,61 @@ +import { CheckCircle2, XCircle, Loader2, AlertCircle } from 'lucide-react' +import { formatDuration } from '@/lib/format' + +export function SectionTitle({ icon: Icon, children }: { icon: React.ComponentType<{ className?: string }>; children: React.ReactNode }) { + return ( +

    + + {children} +

    + ) +} + +export function HistoryRow({ job, onClick }: { job: any; onClick: () => void }) { + const statusIcon = { + succeeded: { icon: CheckCircle2, color: 'text-bear' }, + failed: { icon: XCircle, color: 'text-danger' }, + running: { icon: Loader2, color: 'text-accent', spinning: true }, + pending: { icon: Loader2, color: 'text-muted', spinning: true }, + }[job.status as 'succeeded'] ?? { icon: AlertCircle, color: 'text-muted' } + const Icon = statusIcon.icon + + return ( + + ) +} diff --git a/frontend/src/components/data/SettingsModal.tsx b/frontend/src/components/data/SettingsModal.tsx new file mode 100644 index 0000000..5054ef0 --- /dev/null +++ b/frontend/src/components/data/SettingsModal.tsx @@ -0,0 +1,27 @@ +import { motion } from 'framer-motion' +import { X } from 'lucide-react' + +export function SettingsModal({ title, onClose, children }: { title: string; onClose: () => void; children: React.ReactNode }) { + return ( +
    +
    + +
    +

    {title}

    + +
    +
    + {children} +
    +
    +
    + ) +} diff --git a/frontend/src/components/data/Skeleton.tsx b/frontend/src/components/data/Skeleton.tsx new file mode 100644 index 0000000..8afc405 --- /dev/null +++ b/frontend/src/components/data/Skeleton.tsx @@ -0,0 +1,7 @@ +export function Skeleton({ w = 'w-full', h = 'h-3.5', rounded = 'rounded-sm', className = '' }: { + w?: string; h?: string; rounded?: string; className?: string +}) { + return ( +
    + ) +} diff --git a/frontend/src/components/data/StatCard.tsx b/frontend/src/components/data/StatCard.tsx new file mode 100644 index 0000000..c66cd33 --- /dev/null +++ b/frontend/src/components/data/StatCard.tsx @@ -0,0 +1,312 @@ +import { motion } from 'framer-motion' +import { Loader2, CheckCircle2, Settings, Table2 } from 'lucide-react' +import { formatNumber } from '@/lib/format' +import { fmtDate } from '@/lib/format' +import { Skeleton } from './Skeleton' + +// 卡片能力定义:capKey → 查 capability limits;tierReq → 无权限时显示的档位要求 +export const CARD_META: Record = { + instruments: { capKey: 'quote.by_symbol', tierReq: 'Free' }, + daily: { capKey: 'kline.daily.batch', tierReq: 'Starter+' }, + adj_factor: { capKey: 'adj_factor', tierReq: 'Starter+' }, + enriched: { capKey: '', tierReq: '' }, + minute: { capKey: 'kline.minute.batch', tierReq: 'Pro+' }, + financials: { capKey: 'financial', tierReq: 'Expert' }, +} + +export function Pill({ label, value }: { label: string; value: number | string }) { + return ( +
    +
    {label}
    +
    {value}
    +
    + ) +} + +function CapBadge({ hasCap, isLocal, tierLabel, tierReq, capInfo, localSuffix }: { + hasCap: boolean + isLocal: boolean + tierLabel?: string + tierReq?: string + capInfo?: { rpm: number | null; batch: number | null; subscribe: number | null } | undefined + localSuffix?: string +}) { + if (isLocal) { + return ( + + 本地计算{localSuffix ? ` · ${localSuffix}` : ''} + + ) + } + + if (hasCap && capInfo && tierLabel) { + const parts = [tierLabel, `${capInfo.rpm}/min`] + if (capInfo.batch != null && capInfo.batch > 1) parts.push(`${capInfo.batch}股/批`) + return ( + + {parts.join(' · ')} + + ) + } + + if (!hasCap && tierReq) { + return ( + + 需 {tierReq} + + ) + } + + if (hasCap) { + return ( + + {tierLabel ?? '已授权'} + + ) + } + + return null +} + +export type FieldTab = { label: string; table: string } + +export function StatCard({ + title, hint, stats, isInstrument = false, loading = false, + active = false, done = false, skipped = false, stagePct = 0, + tierKey, capLimits, tierLabel, + auto, onSettings, onShowFields, settingsOpen, subLabel, localBadgeSuffix, fieldTabs, +}: { + title: string + hint: string + stats: any | null | undefined + isInstrument?: boolean + loading?: boolean + active?: boolean + done?: boolean + skipped?: boolean + stagePct?: number + tierKey?: string + capLimits?: Record + tierLabel?: string + onSettings?: () => void + onShowFields?: (table?: string) => void + settingsOpen?: boolean + auto?: boolean + subLabel?: string + localBadgeSuffix?: string + // 多表字段入口: [{label: '维表', table: 'index_instruments'}, ...] + // 提供时渲染多个图标按钮(每个对应一张表的字段说明); 否则回退到单个 onShowFields + fieldTabs?: FieldTab[] +}) { + const empty = loading || !stats || (stats.rows === 0 && !stats.trading_days && !stats.fields) + const borderCls = active + ? 'border-accent/50' + : done + ? 'border-bear/30' + : 'border-border' + const bgCls = active ? 'bg-accent/[0.03]' : 'bg-surface' + + const meta = tierKey ? CARD_META[tierKey] : undefined + const isLocal = meta?.capKey === '' + const capInfo = meta?.capKey ? capLimits?.[meta.capKey] : undefined + const hasCap = isLocal || !!capInfo + + // 渲染字段说明入口图标 + // - fieldTabs 提供时: 返回 null (图标由 renderSubLabelInline 内联到文字后) + // - 否则: 单个图标按钮 (onShowFields) + const renderFieldButtons = () => { + if (fieldTabs && fieldTabs.length > 0) return null + if (onShowFields) { + return ( + + ) + } + return null + } + + // 单个图标按钮 (复用样式) + const fieldIconButton = (tab: FieldTab) => ( + + ) + + // subLabel 文本内容 (不含图标) + const subLabelText = subLabel + ?? (isInstrument + ? `标的 · ${((stats?.named ?? stats?.rows) ?? 0).toLocaleString()} 个含名称` + : stats?.fields + ? '字段 · 复权 · 技术指标' + : title === '日 K' && stats?.trading_days + ? '日 · A股标的 · 日线' + : stats?.trading_days && !stats?.rows + ? '日 · A股标的 · 分钟级' + : (() => { + const parts = [`行 · ${(stats?.symbols_covered ?? 0)} 只标的`] + if (stats?.trading_days) parts.push(`· ${stats.trading_days} 日`) + return parts.join(' ') + })()) + + // 有 fieldTabs 时: 把 subLabel 按分隔符拆开, 每个匹配词后面内联图标 + // 例如 "日 · 维表 · 日K · 指标" → 日 · 维表[icon] · 日K[icon] · 指标[icon] + const renderSubLabelInline = () => { + if (!fieldTabs || fieldTabs.length === 0) { + return <>{subLabelText}{renderFieldButtons()} + } + const labels = fieldTabs.map(t => t.label) + // 按非字母数字汉字的分隔符拆分, 保留分隔符 + const tokens = subLabelText.split(/(\s*·\s*|\s+)/).filter(t => t !== '') + const used = new Set() + return ( + <> + {tokens.map((tok, i) => { + const trimmed = tok.trim() + // 跳过纯分隔符 + if (trimmed === '' || trimmed === '·') return {tok} + // 匹配某个 tab label (整体匹配, 避免部分子串误命中) + const idx = labels.indexOf(trimmed) + if (idx >= 0 && !used.has(trimmed)) { + used.add(trimmed) + return {tok}{fieldIconButton(fieldTabs[idx])} + } + return {tok} + })} + + ) + } + + return ( +
    +
    +

    {title}

    +
    + {auto !== undefined && !loading && ( + + + {auto ? '自动' : '关闭'} + + )} + {active && } + {done && !active && !skipped && } + {skipped && !active && ( + + 本次跳过 + + )} + {onSettings && ( + + )} +
    +
    + +
    {hint}
    + +
    + {loading ? ( + + ) : ( + + )} +
    + +
    + {loading ? ( + <> + + + + ) : empty ? ( + <> +
    +
    + 暂无数据{renderFieldButtons()} +
    + + ) : ( + <> +
    + {stats.fields + ? stats.fields + : stats.trading_days && !stats.rows + ? stats.trading_days.toLocaleString() + : formatNumber(stats.rows)} +
    +
    + {renderSubLabelInline()} +
    + + )} +
    + +
    + {loading ? ( + <> +
    +
    + + ) : empty ? ( + <> +
    + {isInstrument ? '快照日' : '起'} + +
    +
    + {isInstrument ? '标的数' : '止'} + +
    + + ) : ( + <> +
    + {isInstrument ? '快照日' : '起'} + {fmtDate(isInstrument ? stats.latest_as_of : stats.earliest_date)} +
    +
    + {isInstrument ? '标的数' : '止'} + {isInstrument ? String(stats.rows) : fmtDate(stats.latest_date)} +
    + + )} +
    + + {active && stagePct > 0 && ( +
    + +
    + )} +
    + ) +} diff --git a/frontend/src/components/ext-data/CreateExtDialog.tsx b/frontend/src/components/ext-data/CreateExtDialog.tsx new file mode 100644 index 0000000..2c7c995 --- /dev/null +++ b/frontend/src/components/ext-data/CreateExtDialog.tsx @@ -0,0 +1,383 @@ +import { useRef, useState } from 'react' +import { useMutation, useQueryClient } from '@tanstack/react-query' +import { motion } from 'framer-motion' +import { X, Loader2, Upload, Plus, AlertCircle, Tag, Clock } from 'lucide-react' +import { api, type ExtDataField } from '@/lib/api' +import { QK } from '@/lib/queryKeys' + +export function CreateExtDialog({ onClose }: { onClose: () => void }) { + const qc = useQueryClient() + const [id, setId] = useState('') + const [label, setLabel] = useState('') + const [description, setDescription] = useState('') + const [mode, setMode] = useState<'snapshot' | 'timeseries'>('snapshot') + const [fields, setFields] = useState([]) + const [error, setError] = useState('') + const detectFileRef = useRef(null) + const [detecting, setDetecting] = useState(false) + const [dragOver, setDragOver] = useState(false) + const [symbolMap, setSymbolMap] = useState>({}) + const [codeMap, setCodeMap] = useState>({}) + const [matchStatus, setMatchStatus] = useState<'none' | 'partial' | 'full'>('none') + const [selectMapping, setSelectMapping] = useState<{ fields: { name: string; dtype: string; label: string }[]; need: 'symbol' | 'code' | 'both' } | null>(null) + + const create = useMutation({ + mutationFn: () => { + const userF = fields.filter((f) => f.name.trim() && f.name !== 'symbol' && f.name !== 'code') + return api.extDataCreate({ + id, + label, + mode, + fields: [ + { name: 'symbol', dtype: 'string', label: '标的代码' }, + { name: 'code', dtype: 'string', label: '代码' }, + ...userF, + ], + description: description.trim() || undefined, + symbol_map: symbolMap, + code_map: codeMap, + }) + }, + onSuccess: () => { + qc.invalidateQueries({ queryKey: QK.extData }) + onClose() + }, + onError: (err) => setError(String(err)), + }) + + const addField = () => + setFields([...fields, { name: '', dtype: 'string', label: '' }]) + + const removeField = (i: number) => + setFields(fields.filter((_, idx) => idx !== i)) + + const updateField = (i: number, key: keyof ExtDataField, val: string) => + setFields(fields.map((f, idx) => (idx === i ? { ...f, [key]: val } : f))) + + const valid = id.trim() && label.trim() && fields.some((f) => f.name.trim()) && matchStatus !== 'none' + + const processDetection = ( + detected: { name: string; dtype: string; label: string }[], + symCands: string[], + codeCands: string[], + ) => { + let sm: Record = {} + let cm: Record = {} + let status: 'none' | 'partial' | 'full' = 'none' + + if (symCands.length === 1 && codeCands.length === 1) { + sm = { type: 'mapped', col: symCands[0] } + cm = { type: 'mapped', col: codeCands[0] } + status = 'full' + } else if (symCands.length === 1 && codeCands.length === 0) { + sm = { type: 'mapped', col: symCands[0] } + cm = { type: 'computed', from: 'symbol', method: 'strip_exchange' } + status = 'full' + } else if (symCands.length === 0 && codeCands.length === 1) { + cm = { type: 'mapped', col: codeCands[0] } + sm = { type: 'computed', from: 'code', method: 'append_exchange' } + status = 'full' + } else if (symCands.length > 1 || codeCands.length > 1) { + setSelectMapping({ + fields: detected, + need: symCands.length > 0 && codeCands.length > 0 ? 'both' : symCands.length > 0 ? 'symbol' : 'code', + }) + setFields(detected) + return + } else { + setSelectMapping({ fields: detected, need: 'both' }) + setFields(detected) + return + } + + setSymbolMap(sm) + setCodeMap(cm) + setMatchStatus(status) + setFields(detected) + setSelectMapping(null) + } + + const handleDetectFile = (e: React.ChangeEvent) => { + const file = e.target.files?.[0] + if (!file) return + e.target.value = '' + setDetecting(true); setError(''); setSelectMapping(null) + api.extDataDetectFields(file) + .then((res) => { + processDetection(res.fields, res.symbol_candidates, res.code_candidates) + }) + .catch((err) => setError(String(err))) + .finally(() => setDetecting(false)) + } + + const userFields = fields.filter(f => f.name !== 'symbol' && f.name !== 'code') + + return ( +
    +
    + +
    +
    +
    +

    新增扩展数据

    +

    + 接入自有数据,与标的自动关联(第三方接口或CSV/Excel),支持概念、人气、资金流、舆情、研报评分标签等场景 +

    +
    + +
    +
    + +
    +
    +
    数据类型
    +
    + {(['snapshot', 'timeseries'] as const).map((m) => { + const active = mode === m + return ( + + ) + })} +
    +
    + +
    +
    +
    显示名称
    + setLabel(e.target.value)} + placeholder={mode === 'snapshot' ? '例: 概念' : '例: 资金流'} + className="w-full h-9 px-3 rounded-lg bg-base border border-border text-xs text-foreground placeholder:text-muted/40 focus:outline-none focus:ring-1 focus:ring-accent/30 focus:border-accent/50 transition-shadow" + /> +
    +
    +
    标识符
    + setId(e.target.value.replace(/[^a-zA-Z0-9_]/g, ''))} + placeholder={mode === 'snapshot' ? '例: concept' : '例: money_flow'} + className="w-full h-9 px-3 rounded-lg bg-base border border-border text-xs text-foreground font-mono placeholder:text-muted/40 focus:outline-none focus:ring-1 focus:ring-accent/30 focus:border-accent/50 transition-shadow" + /> +
    +
    + +
    +
    描述
    + setDescription(e.target.value)} + placeholder="扩展数据 · 与标的 JOIN(可选自定义描述)" + className="w-full h-9 px-3 rounded-lg bg-base border border-border text-xs text-foreground placeholder:text-muted/40 focus:outline-none focus:ring-1 focus:ring-accent/30 focus:border-accent/50 transition-shadow" + /> +
    + +
    +
    字段定义
    + + + + {selectMapping && ( + +
    + 未自动识别到标的代码,请选择哪一列作为标的代码(symbol) +
    +
    + {selectMapping.fields.map(f => ( + + ))} + +
    +
    + )} + + {userFields.length === 0 ? ( +
    detectFileRef.current?.click()} + onDragOver={e => { e.preventDefault(); setDragOver(true) }} + onDragLeave={() => setDragOver(false)} + onDrop={e => { + e.preventDefault() + setDragOver(false) + const file = e.dataTransfer.files[0] + if (file) { setDetecting(true); setError(''); setSelectMapping(null); api.extDataDetectFields(file).then(res => { processDetection(res.fields, res.symbol_candidates, res.code_candidates); }).catch(err => setError(String(err))).finally(() => setDetecting(false)) } + }} + className={`rounded-xl border-2 border-dashed py-6 flex flex-col items-center justify-center gap-2 cursor-pointer transition-colors ${ + dragOver ? 'border-accent bg-accent/[0.06]' : detecting ? 'border-border/40 pointer-events-none' : 'border-border/30 hover:border-accent/40 hover:bg-accent/[0.02]' + }`} + > + {detecting ? ( + <>检测字段中… + ) : ( + <> + + 上传数据文件(CSV / Excel)自动识别数据格式 + 自动识别列名和类型,symbol 列自动匹配 + + )} +
    + ) : ( + <> +
    + + +
    +
    +
    + 标的代码 + symbol + 文本 + {matchStatus !== 'none' + ? + {symbolMap.type === 'mapped' ? `← ${symbolMap.col}` : '← 计算'} + + : } +
    +
    + 代码 + code + 文本 + {matchStatus !== 'none' + ? + {codeMap.type === 'mapped' ? `← ${codeMap.col}` : codeMap.method === 'strip_exchange' ? '← symbol截取' : '← 推算'} + + : } +
    + {userFields.map((f) => { + const idx = fields.indexOf(f) + return ( +
    + updateField(idx, 'label', e.target.value)} + placeholder="显示名" + className="w-[72px] h-7 px-2 rounded-md border border-border bg-base text-[11px] text-foreground placeholder:text-muted/40 focus:outline-none focus:border-accent/40" + /> + updateField(idx, 'name', e.target.value)} + placeholder="字段名" + className="flex-1 h-7 px-2 rounded-md border border-border bg-base text-[11px] font-mono text-foreground placeholder:text-muted/40 focus:outline-none focus:border-accent/40" + /> + + +
    + ) + })} +
    + + )} +
    + + {error && ( +
    {error}
    + )} +
    + +
    +
    数据需自行维护和更新,系统不会自动同步
    +
    + + +
    +
    +
    +
    + ) +} diff --git a/frontend/src/components/ext-data/EditExtDialog.tsx b/frontend/src/components/ext-data/EditExtDialog.tsx new file mode 100644 index 0000000..acae389 --- /dev/null +++ b/frontend/src/components/ext-data/EditExtDialog.tsx @@ -0,0 +1,252 @@ +import { useRef, useState } from 'react' +import { useMutation, useQueryClient } from '@tanstack/react-query' +import { motion } from 'framer-motion' +import { X, Loader2, Upload } from 'lucide-react' +import { api, type ExtDataConfig, type ExtDataField } from '@/lib/api' +import { QK } from '@/lib/queryKeys' + +export function EditExtDialog({ config, onClose }: { config: ExtDataConfig; onClose: () => void }) { + const qc = useQueryClient() + const [label, setLabel] = useState(config.label) + const [description, setDescription] = useState(config.description ?? '') + const [fields, setFields] = useState([...config.fields]) + const [error, setError] = useState('') + const detectFileRef = useRef(null) + const [detecting, setDetecting] = useState(false) + const [symbolMapping, setSymbolMapping] = useState<{ candidates: string[]; file: File } | null>(null) + + const update = useMutation({ + mutationFn: () => + api.extDataUpdate(config.id, { + label: label.trim(), + fields: fields.filter((f) => f.name.trim()), + description: description.trim() || '', + }), + onSuccess: () => { + qc.invalidateQueries({ queryKey: QK.extData }) + onClose() + }, + onError: (err) => setError(String(err)), + }) + + const addField = () => + setFields([...fields, { name: '', dtype: 'string', label: '' }]) + + const removeField = (i: number) => + setFields(fields.filter((_, idx) => idx !== i)) + + const updateField = (i: number, key: keyof ExtDataField, val: string) => + setFields(fields.map((f, idx) => (idx === i ? { ...f, [key]: val } : f))) + + const valid = label.trim() && fields.some((f) => f.name.trim()) + + const applyDetectedFields = (detected: { name: string; dtype: string; label: string }[]) => { + const rest = detected.filter(f => f.name !== 'symbol') + setFields([ + { name: 'symbol', dtype: 'string', label: '标的代码' }, + ...rest, + ]) + } + + const handleDetectFile = (e: React.ChangeEvent) => { + const file = e.target.files?.[0] + if (!file) return + e.target.value = '' + setDetecting(true); setError(''); setSymbolMapping(null) + api.extDataDetectFields(file) + .then((res) => { + const hasSym = res.symbol_candidates.length > 0 + const hasCode = res.code_candidates.length > 0 + if (hasSym || hasCode) { + applyDetectedFields(res.fields) + } else { + const candidates = res.fields.map(f => f.name) + setSymbolMapping({ candidates, file }) + } + }) + .catch((err) => setError(String(err))) + .finally(() => setDetecting(false)) + } + + const handleSymbolMap = (_col: string) => { + if (!symbolMapping) return + setDetecting(true); setError('') + const rest = fields.filter(f => f.name !== 'symbol') + setFields([{ name: 'symbol', dtype: 'string', label: '标的代码' }, ...rest]) + setSymbolMapping(null) + setDetecting(false) + } + + return ( +
    +
    + +
    +

    编辑扩展数据

    + +
    + +
    +
    +
    + +
    + {config.id} +
    +
    +
    + +
    + {config.mode === 'snapshot' ? '快照型' : '时序型'} +
    +
    +
    + +
    + + setLabel(e.target.value)} + className="w-full h-8 px-3 rounded-btn bg-base border border-border text-xs text-foreground placeholder:text-muted/40 focus:outline-none focus:border-accent/50" + /> +
    + +
    + + setDescription(e.target.value)} + placeholder="可选,简要说明数据的用途" + className="w-full h-8 px-3 rounded-btn bg-base border border-border text-xs text-foreground placeholder:text-muted/40 focus:outline-none focus:border-accent/50" + /> +
    + +
    +
    + +
    + + + +
    +
    + {symbolMapping && ( +
    +
    未找到 symbol 列,请选择哪一列作为标的代码:
    +
    + {symbolMapping.candidates.map(col => ( + + ))} + +
    +
    + )} +
    + {fields.map((f, i) => { + const isBuiltin = f.name === 'symbol' || f.name === 'name' + return ( +
    + updateField(i, 'label', e.target.value)} + placeholder="显示名" + disabled={isBuiltin} + className={`w-20 h-7 px-2 rounded-btn border text-[11px] text-foreground placeholder:text-muted/40 focus:outline-none focus:border-accent/50 ${ + isBuiltin + ? 'bg-elevated/50 border-border text-muted cursor-not-allowed' + : 'bg-base border-border' + }`} + /> + updateField(i, 'name', e.target.value)} + placeholder="字段名 (英文)" + disabled={isBuiltin} + className={`flex-1 h-7 px-2 rounded-btn border text-[11px] font-mono placeholder:text-muted/40 focus:outline-none focus:border-accent/50 ${ + isBuiltin + ? 'bg-elevated/50 border-border text-muted cursor-not-allowed' + : 'bg-base border-border' + }`} + /> + + {!isBuiltin && fields.length > 3 && ( + + )} + {isBuiltin &&
    } +
    + ) + })} +
    +
    + + {error && ( +
    {error}
    + )} +
    + +
    + + +
    + +
    + ) +} diff --git a/frontend/src/components/ext-data/ExtDataApiPanel.tsx b/frontend/src/components/ext-data/ExtDataApiPanel.tsx new file mode 100644 index 0000000..5cd3700 --- /dev/null +++ b/frontend/src/components/ext-data/ExtDataApiPanel.tsx @@ -0,0 +1,79 @@ +import { Check, Copy } from 'lucide-react' +import type { ExtDataConfig } from '@/lib/api' + +export function ExtDataApiPanel({ config, copied, setCopied }: { + config: ExtDataConfig + copied: boolean + setCopied: (v: boolean) => void +}) { + const endpoint = `POST /api/ext-data/${config.id}/ingest` + + const exampleRow: Record = { symbol: '000001.SZ' } + for (const f of config.fields) { + if (f.name === 'symbol' || f.name === 'code') continue + exampleRow[f.name] = f.dtype === 'int' ? 100 : f.dtype === 'float' ? 1.5 : f.dtype === 'bool' ? true : '示例' + } + if (config.fields.some(f => f.name === 'code')) { + exampleRow['code'] = '000001' + } + const exampleBody = { + date: config.mode === 'timeseries' ? '2025-01-15' : undefined, + rows: [exampleRow], + } + const exampleJson = JSON.stringify(exampleBody, null, 2) + const curlCmd = `curl -X POST http://localhost:${window.location.port || '3018'}/api/ext-data/${config.id}/ingest \\ + -H 'Content-Type: application/json' \\ + -d '${JSON.stringify(exampleBody)}'` + + const handleCopy = (text: string) => { + navigator.clipboard.writeText(text).then(() => { + setCopied(true) + setTimeout(() => setCopied(false), 2000) + }) + } + + return ( +
    +
    +
    接口端点
    +
    + {endpoint} + +
    +
    + +
    +
    请求体示例
    +
    +          {exampleJson}
    +        
    +
    + +
    +
    + cURL 示例 + +
    +
    +          {curlCmd}
    +        
    +
    + +
    + {config.mode === 'snapshot' ? ( + <>date 可选,默认当天;每次写入覆盖同日期数据 + ) : ( + <>date 必填,指定交易日;按日期分区存储 + )} +
    +
    + ) +} diff --git a/frontend/src/components/ext-data/ExtDataPullPanel.tsx b/frontend/src/components/ext-data/ExtDataPullPanel.tsx new file mode 100644 index 0000000..36ad379 --- /dev/null +++ b/frontend/src/components/ext-data/ExtDataPullPanel.tsx @@ -0,0 +1,212 @@ +import { useState } from 'react' +import { Loader2, Search, RefreshCw, Check } from 'lucide-react' +import { api, type ExtDataConfig } from '@/lib/api' + +export function ExtDataPullPanel({ config, onSaved }: { + config: ExtDataConfig + onSaved: () => void +}) { + const pull = config.pull + const [url, setUrl] = useState(pull?.url ?? '') + const [method, setMethod] = useState(pull?.method ?? 'GET') + const [headerStr, setHeaderStr] = useState( + pull?.headers ? JSON.stringify(pull.headers, null, 2) : '' + ) + const [body, setBody] = useState(pull?.body ?? '') + const [responsePath, setResponsePath] = useState(pull?.response_path ?? '') + const [fieldMapStr, setFieldMapStr] = useState( + pull?.field_map ? JSON.stringify(pull.field_map, null, 2) : '' + ) + const [schedule, setSchedule] = useState(pull?.schedule_minutes ?? 1440) + const [enabled, setEnabled] = useState(pull?.enabled ?? false) + const [saving, setSaving] = useState(false) + const [testing, setTesting] = useState(false) + const [running, setRunning] = useState(false) + const [testResult, setTestResult] = useState<{ total_rows: number; preview: Record[]; has_symbol: boolean } | null>(null) + const [error, setError] = useState('') + + const handleSave = () => { + let headers: Record | undefined + if (headerStr.trim()) { + try { headers = JSON.parse(headerStr) } + catch { setError('Headers 不是有效 JSON'); return } + } + let field_map: Record | undefined + if (fieldMapStr.trim()) { + try { field_map = JSON.parse(fieldMapStr) } + catch { setError('字段映射不是有效 JSON'); return } + } + setSaving(true); setError('') + api.extDataPullConfig(config.id, { + url, method, headers, body: body || undefined, + response_path: responsePath, field_map, + schedule_minutes: schedule, enabled, + }).then(() => onSaved()) + .catch(e => setError(e.message || '保存失败')) + .finally(() => setSaving(false)) + } + + const handleTest = () => { + setTesting(true); setError(''); setTestResult(null) + let headers: Record | undefined + if (headerStr.trim()) { + try { headers = JSON.parse(headerStr) } + catch { setError('Headers 不是有效 JSON'); setTesting(false); return } + } + let field_map: Record | undefined + if (fieldMapStr.trim()) { + try { field_map = JSON.parse(fieldMapStr) } + catch { setError('字段映射不是有效 JSON'); setTesting(false); return } + } + api.extDataPullConfig(config.id, { + url, method, headers, body: body || undefined, + response_path: responsePath, field_map, + schedule_minutes: schedule, enabled, + }).then(() => api.extDataPullTest(config.id)) + .then(r => { setTestResult(r); onSaved() }) + .catch(e => setError(e.message || '测试失败')) + .finally(() => setTesting(false)) + } + + const handleRun = () => { + setRunning(true); setError('') + api.extDataPullRun(config.id) + .then(() => onSaved()) + .catch(e => setError(e.message || '执行失败')) + .finally(() => setRunning(false)) + } + + return ( +
    +
    + + setUrl(e.target.value)} + placeholder="https://api.example.com/data" + className="flex-1 min-w-0 rounded-md border border-border bg-elevated px-2.5 py-1.5 text-[11px] font-mono text-foreground placeholder:text-muted/50" + /> +
    + +
    +
    Headers (JSON,可选)
    +

dYQa|ep222R8UcT4bc(Q6?dsH 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