完善知行短线
This commit is contained in:
222
backend_run.log
222
backend_run.log
@@ -155,3 +155,225 @@ INFO: Waiting for application startup.
|
||||
INFO: Application startup complete.
|
||||
INFO: 127.0.0.1:55384 - "GET /api/health HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:55388 - "GET /api/stock/000001.SZ/chips?adjust=qfq HTTP/1.1" 401 Unauthorized
|
||||
INFO: 127.0.0.1:55749 - "GET /api/stock/000001.SZ/chips?adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:55760 - "GET /api/stock/000001.SZ/chips?adjust=bfq&date=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56017 - "GET /api/auth/me HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56029 - "GET /api/preferences HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56030 - "GET /api/stocks?search=%E5%8D%AB%E6%98%9F%E5%8C%96%E5%AD%A6&sort=symbol&order=asc&limit=100&offset=0 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56031 - "GET /api/stocks/facets HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56040 - "GET /api/trades?ts_code=002648.SZ HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56044 - "GET /api/watchlist HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56041 - "GET /api/screener/preview/002648.SZ?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56051 - "GET /api/screener/preview/002648.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56054 - "GET /api/stock/002648.SZ/chips?date=2026-08-14&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56062 - "GET /api/stock/002648.SZ/chips?date=2026-08-14&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56065 - "GET /api/stock/002648.SZ/chips?date=2026-04-29&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56071 - "GET /api/stock/002648.SZ/chips?date=2026-08-14&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56075 - "GET /api/stock/002648.SZ/chips?date=2026-03-11&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56081 - "GET /api/stock/002648.SZ/chips?date=2026-08-14&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56084 - "GET /api/stock/002648.SZ/chips?date=2026-05-08&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56089 - "GET /api/stock/002648.SZ/chips?date=2026-08-14&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56096 - "GET /api/stock/002648.SZ/chips?date=2026-03-10&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56100 - "GET /api/stock/002648.SZ/chips?date=2025-12-25&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56111 - "GET /api/stock/002648.SZ/chips?date=2025-10-24&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56116 - "GET /api/stock/002648.SZ/chips?date=2025-09-05&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56121 - "GET /api/stock/002648.SZ/chips?date=2025-06-26&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56106 - "GET /api/stock/002648.SZ/chips?date=2025-12-24&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56129 - "GET /api/stock/002648.SZ/chips?date=2025-09-16&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56133 - "GET /api/stock/002648.SZ/chips?date=2025-06-12&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56139 - "GET /api/stock/002648.SZ/chips?date=2025-03-28&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56145 - "GET /api/stock/002648.SZ/chips?date=2024-12-30&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56149 - "GET /api/stock/002648.SZ/chips?date=2024-11-13&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56156 - "GET /api/stock/002648.SZ/chips?date=2024-09-04&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56160 - "GET /api/stock/002648.SZ/chips?date=2024-10-22&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56167 - "GET /api/stock/002648.SZ/chips?date=2025-04-29&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56171 - "GET /api/stock/002648.SZ/chips?date=2025-07-09&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56177 - "GET /api/stock/002648.SZ/chips?date=2025-09-24&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56196 - "GET /api/stock/002648.SZ/chips?date=2025-12-23&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56200 - "GET /api/stock/002648.SZ/chips?date=2026-04-01&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56207 - "GET /api/stock/002648.SZ/chips?date=2026-06-22&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56210 - "GET /api/stock/002648.SZ/chips?date=2026-08-12&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56218 - "GET /api/stock/002648.SZ/chips?date=2026-06-17&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56265 - "GET /api/stock/002648.SZ/chips?date=2026-03-17&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56384 - "GET /api/stock/002648.SZ/chips?date=2026-05-22&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56458 - "GET /api/screener/preview/002648.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56501 - "GET /api/screener/preview/002648.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56520 - "GET /api/screener/preview/002648.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56545 - "GET /api/screener/preview/002648.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56564 - "GET /api/trades?ts_code=002648.SZ HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56568 - "GET /api/screener/preview/002648.SZ?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56571 - "GET /api/watchlist HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56577 - "GET /api/screener/preview/002648.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56581 - "GET /api/trades?ts_code=002648.SZ HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56584 - "GET /api/screener/preview/002648.SZ?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56587 - "GET /api/watchlist HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56589 - "GET /api/screener/preview/002648.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56690 - "GET /api/stock/002648.SZ/chips?date=2026-08-14&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56693 - "GET /api/stock/002648.SZ/chips?date=2026-08-14&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56699 - "GET /api/stock/002648.SZ/chips?date=2026-08-14&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56715 - "GET /api/auth/me HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56727 - "GET /api/preferences HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56731 - "GET /api/stocks/facets HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56730 - "GET /api/stocks?search=%E5%8D%AB%E6%98%9F%E5%8C%96%E5%AD%A6&sort=symbol&order=asc&limit=100&offset=0 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56733 - "GET /api/trades?ts_code=002648.SZ HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56734 - "GET /api/screener/preview/002648.SZ?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56736 - "GET /api/watchlist HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56739 - "GET /api/screener/preview/002648.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56747 - "GET /api/stock/002648.SZ/chips?date=2026-08-14&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56749 - "GET /api/stock/002648.SZ/chips?date=2026-08-14&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56754 - "GET /api/stock/002648.SZ/chips?date=2026-08-14&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56756 - "GET /api/stock/002648.SZ/chips?date=2026-06-11&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56772 - "GET /api/stock/002648.SZ/chips?date=2026-08-14&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56781 - "GET /api/auth/me HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56793 - "GET /api/preferences HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56795 - "GET /api/stocks/facets HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56794 - "GET /api/stocks?search=%E5%8D%AB%E6%98%9F%E5%8C%96%E5%AD%A6&sort=symbol&order=asc&limit=100&offset=0 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56805 - "GET /api/trades?ts_code=002648.SZ HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56806 - "GET /api/screener/preview/002648.SZ?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56809 - "GET /api/watchlist HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56811 - "GET /api/screener/preview/002648.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56818 - "GET /api/stock/002648.SZ/chips?date=2026-08-14&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56828 - "GET /api/stock/002648.SZ/chips?date=2026-08-13&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56835 - "GET /api/stock/002648.SZ/chips?date=2026-03-30&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56863 - "GET /api/stock/002648.SZ/chips?date=2026-07-23&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56882 - "GET /api/stocks?sort=symbol&order=asc&limit=100&offset=0 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56887 - "GET /api/stocks/facets HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56874 - "GET /api/market/overview HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56900 - "GET /api/watchlist HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56898 - "GET /api/trades?ts_code=000006.SZ HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56899 - "GET /api/screener/preview/000006.SZ?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56904 - "GET /api/screener/preview/000006.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56907 - "GET /api/stock/000006.SZ/chips?date=2026-08-14&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56916 - "GET /api/screener/preview/000006.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56923 - "GET /api/screener/preview/000006.SZ?limit=800&adjust=qfq&timeframe=1d&end=2021-04-07 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56929 - "GET /api/screener/preview/000006.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56931 - "GET /api/screener/preview/000006.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56940 - "GET /api/screener/preview/000006.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56943 - "GET /api/screener/preview/000006.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56947 - "GET /api/trades?ts_code=000001.SZ HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56951 - "GET /api/screener/preview/000001.SZ?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56958 - "GET /api/screener/preview/000001.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56970 - "GET /api/screener/preview/000001.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56979 - "GET /api/screener/preview/000001.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56975 - "GET /api/screener/preview/000001.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56985 - "GET /api/screener/preview/000001.SZ?limit=800&adjust=qfq&timeframe=1d&end=2021-04-07 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56990 - "GET /api/screener/preview/000001.SZ?limit=800&adjust=qfq&timeframe=1d&end=2017-12-19 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56998 - "GET /api/trades?ts_code=000006.SZ HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57000 - "GET /api/screener/preview/000006.SZ?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57004 - "GET /api/screener/preview/000006.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57012 - "GET /api/stocks?sort=symbol&order=asc&limit=100&offset=0 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57017 - "GET /api/stocks?search=%E5%8C%96%E5%AD%A6%E7%BB%99&sort=symbol&order=asc&limit=100&offset=0 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57019 - "GET /api/stocks?search=%E5%8C%96%E5%AD%A6&sort=symbol&order=asc&limit=100&offset=0 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57024 - "GET /api/stocks?sort=symbol&order=asc&limit=100&offset=0 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57026 - "GET /api/stocks?search=%E5%8D%AB%E6%98%9F&sort=symbol&order=asc&limit=100&offset=0 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57037 - "GET /api/watchlist HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57034 - "GET /api/trades?ts_code=002648.SZ HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57035 - "GET /api/screener/preview/002648.SZ?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57039 - "GET /api/screener/preview/002648.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57048 - "GET /api/screener/preview/002648.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57061 - "GET /api/watchlist HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57058 - "GET /api/trades?ts_code=600118.SH HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57059 - "GET /api/screener/preview/600118.SH?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57066 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57099 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57103 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2021-04-07 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57131 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57134 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57139 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57143 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57136 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57146 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57151 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57153 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57917 - "GET /api/auth/me HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57927 - "GET /api/preferences HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57931 - "GET /api/stocks?search=%E5%8D%AB%E6%98%9F&sort=symbol&order=asc&limit=100&offset=0 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57932 - "GET /api/stocks/facets HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57937 - "GET /api/trades?ts_code=600118.SH HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57939 - "GET /api/watchlist HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57938 - "GET /api/screener/preview/600118.SH?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57944 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58070 - "GET /api/auth/me HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58075 - "GET /api/preferences HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58086 - "GET /api/stocks/facets HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58085 - "GET /api/stocks?search=%E5%8D%AB%E6%98%9F&sort=symbol&order=asc&limit=100&offset=0 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58088 - "GET /api/trades?ts_code=600118.SH HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58091 - "GET /api/watchlist HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58089 - "GET /api/screener/preview/600118.SH?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58096 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58098 - "GET /api/stock/600118.SH/chips?date=2026-08-14&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58110 - "GET /api/stock/600118.SH/chips?date=2026-03-25&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58114 - "GET /api/stock/600118.SH/chips?date=2026-08-14&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58122 - "GET /api/stock/600118.SH/chips?date=2026-04-28&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58134 - "GET /api/stock/600118.SH/chips?date=2026-06-17&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58127 - "GET /api/stock/600118.SH/chips?date=2026-05-07&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58139 - "GET /api/stock/600118.SH/chips?date=2026-06-30&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58145 - "GET /api/stock/600118.SH/chips?date=2026-08-03&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58150 - "GET /api/stock/600118.SH/chips?date=2026-07-16&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58155 - "GET /api/stock/600118.SH/chips?date=2026-08-13&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58166 - "GET /api/stock/600118.SH/chips?date=2026-07-28&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58161 - "GET /api/stock/600118.SH/chips?date=2026-08-14&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58173 - "GET /api/stock/600118.SH/chips?date=2026-06-12&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58178 - "GET /api/stock/600118.SH/chips?date=2026-05-29&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58186 - "GET /api/stock/600118.SH/chips?date=2026-08-14&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58195 - "GET /api/stock/600118.SH/chips?date=2026-04-28&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58202 - "GET /api/stock/600118.SH/chips?date=2026-06-02&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58207 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58210 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58213 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58226 - "GET /api/stock/600118.SH/chips?date=2026-06-17&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58241 - "GET /api/screener/preview/002648.SZ?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58247 - "GET /api/stock/002648.SZ/chips?date=2026-08-14&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58222 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58249 - "GET /api/screener/preview/002648.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58237 - "GET /api/stock/600118.SH/chips?date=2025-08-07&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58240 - "GET /api/trades?ts_code=002648.SZ HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58258 - "GET /api/stock/002648.SZ/chips?date=2026-04-27&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58219 - "GET /api/stock/600118.SH/chips?date=2026-06-15&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58270 - "GET /api/screener/preview/002648.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58273 - "GET /api/screener/preview/002648.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58277 - "GET /api/stock/002648.SZ/chips?date=2026-06-16&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58282 - "GET /api/stock/002648.SZ/chips?date=2026-03-02&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58288 - "GET /api/stock/002648.SZ/chips?date=2026-04-14&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58293 - "GET /api/stock/002648.SZ/chips?date=2026-06-01&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58298 - "GET /api/stock/002648.SZ/chips?date=2026-06-16&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58305 - "GET /api/stock/002648.SZ/chips?date=2026-08-14&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58309 - "GET /api/stock/002648.SZ/chips?date=2026-06-09&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58315 - "GET /api/stock/002648.SZ/chips?date=2026-06-05&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58323 - "GET /api/stock/002648.SZ/chips?date=2026-04-03&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58326 - "GET /api/screener/preview/002648.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58329 - "GET /api/screener/preview/002648.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58333 - "GET /api/screener/preview/002648.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58341 - "GET /api/screener/preview/002648.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58346 - "GET /api/screener/preview/002648.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58350 - "GET /api/stock/002648.SZ/chips?date=2026-08-14&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58356 - "GET /api/stock/002648.SZ/chips?date=2026-06-24&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58364 - "GET /api/stock/002648.SZ/chips?date=2026-04-30&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58368 - "GET /api/screener/preview/002648.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58371 - "GET /api/screener/preview/002648.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58374 - "GET /api/stock/002648.SZ/chips?date=2026-03-06&adjust=qfq HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58392 - "GET /api/auth/me HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58400 - "GET /api/preferences HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58410 - "GET /api/stocks/facets HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58409 - "GET /api/stocks?search=%E5%8D%AB%E6%98%9F&sort=symbol&order=asc&limit=100&offset=0 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58414 - "GET /api/trades?ts_code=002648.SZ HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58417 - "GET /api/watchlist HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58415 - "GET /api/screener/preview/002648.SZ?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58422 - "GET /api/screener/preview/002648.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58424 - "GET /api/screener/preview/002648.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58431 - "GET /api/trades?ts_code=600118.SH HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58432 - "GET /api/screener/preview/600118.SH?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58435 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58441 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58444 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58447 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58450 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58698 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58707 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58709 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58766 - "GET /api/trades?ts_code=002648.SZ HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58767 - "GET /api/screener/preview/002648.SZ?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58777 - "GET /api/trades?ts_code=600118.SH HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58769 - "GET /api/screener/preview/002648.SZ?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58778 - "GET /api/screener/preview/600118.SH?limit=500&adjust=qfq&timeframe=1d HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:58782 - "GET /api/screener/preview/600118.SH?limit=800&adjust=qfq&timeframe=1d&end=2024-07-24 HTTP/1.1" 200 OK
|
||||
|
||||
132
frontend/src/indicators/chips.ts
Normal file
132
frontend/src/indicators/chips.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
// 个股筹码峰(Tushare cyq_chips / cyq_perf,同花顺式右侧横向线状直方图)
|
||||
//
|
||||
// 数据不在图表窗口上计算,而是一次性截面(某交易日各价位筹码占比 + 获利比例/平均成本),
|
||||
// 经 extendData 注入、纯 draw 绘制:
|
||||
// - 每个价位一根横线,从主图右缘向左延伸,宽度 ∝ 占比/最大占比(火焰山形态)
|
||||
// - 分界价 = 选中K线的收盘价(refClose):下方为获利盘(红线)、上方为套牢盘(蓝线)
|
||||
// - 平均成本画黄色虚线;右上角小字块:截面日期 / 获利比例 / 平均成本 / 90% 成本区间
|
||||
// figures 为空、calc 返回空行:指标不产生序列值,也不影响主图价格刻度(筹码是覆盖层)。
|
||||
import type { IndicatorTemplate } from 'klinecharts';
|
||||
|
||||
export const CHIPS_NAME = 'pv-chips';
|
||||
|
||||
/** 经 extendData 注入的筹码截面(父组件按 当前窗口末根/十字线 所在周期取数) */
|
||||
export interface ChipsExt {
|
||||
rows: { price: number; percent: number }[]; // percent 为 0~1 占比
|
||||
date?: string; // YYYYMMDD 截面日
|
||||
refClose?: number | null; // 获利/套牢分界价:选中K线收盘(缺省时 draw 退回图表末根收盘)
|
||||
winner?: number | null; // 获利比例 %
|
||||
avg?: number | null; // 平均成本
|
||||
costLow?: number | null; // 90% 成本下沿(cost_5pct)
|
||||
costHigh?: number | null; // 90% 成本上沿(cost_95pct)
|
||||
error?: string | null; // 无数据/出错的提示文案(仍要画出来,用户才知道为何空)
|
||||
}
|
||||
|
||||
// 同花顺筹码峰配色:获利盘红、套牢盘蓝
|
||||
const UP = '#FE354B';
|
||||
const DOWN = '#2F7BFF';
|
||||
const AVG_COLOR = '#F5C518';
|
||||
const LABEL_COLOR = '#9AA0AA';
|
||||
const VALUE_COLOR = '#E8EAED';
|
||||
|
||||
/** 同花顺筹码峰同款:横线最大占主图宽度的比例与上限(px) */
|
||||
const MAX_WIDTH_RATIO = 0.22;
|
||||
const MAX_WIDTH_PX = 150;
|
||||
/** 横条高度上限(px):极度放大时单价位占比条不至于铺满半个主图 */
|
||||
const BAR_HEIGHT_CAP = 24;
|
||||
|
||||
function fmtDate(d?: string): string {
|
||||
return d && d.length === 8 ? `${d.slice(0, 4)}-${d.slice(4, 6)}-${d.slice(6, 8)}` : '—';
|
||||
}
|
||||
|
||||
export const chipsIndicator: IndicatorTemplate<Record<string, never>, unknown, ChipsExt> = {
|
||||
name: CHIPS_NAME,
|
||||
shortName: '筹码',
|
||||
figures: [], // 纯 draw 绘制,无序列图形
|
||||
calc: (d) => d.map(() => ({})),
|
||||
// 返回 true(isCover):跳过框架 figure 渲染(本来也没有 figures),全部自己画
|
||||
draw: ({ ctx, chart, indicator, bounding, yAxis }) => {
|
||||
const ext = indicator.extendData;
|
||||
if (!ext) return true;
|
||||
|
||||
// 右上角统计小字块(画线工具栏是 HTML 层,占顶部 ~36px,文字块从 44px 起)
|
||||
const lines: { label: string; value: string; color: string }[] = [];
|
||||
if (ext.error) {
|
||||
lines.push({ label: '筹码', value: ext.error, color: LABEL_COLOR });
|
||||
} else if (ext.rows.length) {
|
||||
const w = ext.winner;
|
||||
lines.push({ label: `筹码 ${fmtDate(ext.date)}`, value: '', color: LABEL_COLOR });
|
||||
lines.push({
|
||||
label: '获利比例',
|
||||
value: w == null ? '—' : `${w.toFixed(2)}%`,
|
||||
color: w == null ? VALUE_COLOR : w >= 50 ? UP : DOWN,
|
||||
});
|
||||
lines.push({ label: '平均成本', value: ext.avg == null ? '—' : ext.avg.toFixed(2), color: AVG_COLOR });
|
||||
lines.push({
|
||||
label: '90%成本',
|
||||
value: ext.costLow == null || ext.costHigh == null ? '—' : `${ext.costLow.toFixed(2)}~${ext.costHigh.toFixed(2)}`,
|
||||
color: VALUE_COLOR,
|
||||
});
|
||||
}
|
||||
if (lines.length) {
|
||||
ctx.font = '11px sans-serif';
|
||||
ctx.textBaseline = 'top';
|
||||
ctx.textAlign = 'right';
|
||||
let y = bounding.top + 44;
|
||||
for (const ln of lines) {
|
||||
const text = ln.value ? `${ln.label} ${ln.value}` : ln.label;
|
||||
ctx.fillStyle = ln.color;
|
||||
ctx.fillText(text, bounding.right - 4, y);
|
||||
y += 14;
|
||||
}
|
||||
}
|
||||
if (!ext.rows.length) return true;
|
||||
|
||||
// 分界价:选中K线的收盘价(父组件随截面注入;缺省退回图表末根收盘),
|
||||
// <=分界价为获利盘(红)、>分界价为套牢盘(蓝)——同花顺同款
|
||||
const list = chart.getDataList();
|
||||
const close = ext.refClose ?? (list.length ? list[list.length - 1].close : undefined);
|
||||
|
||||
// 价位升序,便于求相邻像素间距(直方图的“条高”)
|
||||
const rows = [...ext.rows].sort((a, b) => a.price - b.price);
|
||||
const maxP = rows.reduce((m, r) => Math.max(m, r.percent), 0);
|
||||
if (maxP <= 0) return true;
|
||||
const maxW = Math.min(bounding.width * MAX_WIDTH_RATIO, MAX_WIDTH_PX);
|
||||
|
||||
// 相邻价位的中位像素间距 → 条高(连续火焰形态;缩到极小时并成实心轮廓)
|
||||
const pitches: number[] = [];
|
||||
for (let i = 1; i < rows.length; i++) {
|
||||
const p = Math.abs(yAxis.convertToPixel(rows[i].price) - yAxis.convertToPixel(rows[i - 1].price));
|
||||
if (p > 0) pitches.push(p);
|
||||
}
|
||||
pitches.sort((a, b) => a - b);
|
||||
const pitch = pitches.length ? pitches[pitches.length >> 1] : 4;
|
||||
const barH = Math.min(BAR_HEIGHT_CAP, Math.max(1, pitch * 0.92));
|
||||
|
||||
for (const r of rows) {
|
||||
const y = yAxis.convertToPixel(r.price);
|
||||
if (y < bounding.top - barH || y > bounding.bottom + barH) continue; // 视口外跳过
|
||||
const w = Math.max(1, (r.percent / maxP) * maxW);
|
||||
ctx.fillStyle = close == null ? 'rgba(154,160,170,0.5)'
|
||||
: r.price <= close ? 'rgba(254,53,75,0.55)' : 'rgba(47,123,255,0.55)';
|
||||
ctx.fillRect(bounding.right - w, y - barH / 2, w, barH);
|
||||
}
|
||||
|
||||
// 平均成本虚线(横贯直方图区)
|
||||
if (ext.avg != null) {
|
||||
const y = yAxis.convertToPixel(ext.avg);
|
||||
if (y >= bounding.top && y <= bounding.bottom) {
|
||||
ctx.save();
|
||||
ctx.strokeStyle = AVG_COLOR;
|
||||
ctx.lineWidth = 1;
|
||||
ctx.setLineDash([4, 3]);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(bounding.right - maxW, y + 0.5);
|
||||
ctx.lineTo(bounding.right, y + 0.5);
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
};
|
||||
23
frontend/src/indicators/index.ts
Normal file
23
frontend/src/indicators/index.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
// 自定义指标注册表:通达信导入的主图指标都在这里追加一项。
|
||||
// 依赖预计算序列的指标(知行)不在此处闭包数据,而是导出模板工厂、由 DetailKLine 注入
|
||||
// 按时间戳取值的访问器(g(),与 pv-boll 等后端序列同款管道)。注意 g 及其闭包的
|
||||
// PV/allData 是组件实例级的(script setup 每次挂载重建),知行模板必须随挂载重注册
|
||||
// 换绑到当前实例——否则永远读首挂实例的数据,切股后画的是第一只股票的线;
|
||||
// 筹码峰等“截面数据 + 纯 draw”指标不闭包实例数据(经 extendData 注入),注册一次即可。
|
||||
import { registerIndicator } from 'klinecharts';
|
||||
import { chipsIndicator } from './chips';
|
||||
import { makeZhixingIndicator, ZHIXING_NAME, type ZhixingGetter } from './zhixing';
|
||||
|
||||
let staticRegistered = false;
|
||||
|
||||
export function registerCustomIndicators(get: ZhixingGetter) {
|
||||
// 知行:同名重注册即替换,把 calc 换绑到本次挂载实例的 g(与 DetailKLine 内
|
||||
// pv-boll/pv-macd 每挂必注册同款;幂等闸曾导致知行只认第一只股票)
|
||||
registerIndicator(makeZhixingIndicator(get));
|
||||
if (staticRegistered) return;
|
||||
staticRegistered = true;
|
||||
registerIndicator(chipsIndicator);
|
||||
}
|
||||
|
||||
export { CHIPS_NAME, type ChipsExt } from './chips';
|
||||
export { ZHIXING_NAME, ZHIXING_TREND_COLOR, DKX_PERIODS, computeZhixingSeries } from './zhixing';
|
||||
173
frontend/src/indicators/zhixing.md
Normal file
173
frontend/src/indicators/zhixing.md
Normal file
@@ -0,0 +1,173 @@
|
||||
# 知行指标移植文档(通达信 → 任意平台)
|
||||
|
||||
> 供后续导入到其他项目/平台使用的完整规格:公式原文、参数、数值口径、参考实现、
|
||||
> 校验向量、显示规范。框架无关部分可直接拷贝;klinecharts v10 集成见第八节。
|
||||
> 本仓库实现:`zhixing.ts`(算法+模板)/ `index.ts`(注册表)/ `DetailKLine.vue`(数据管道)。
|
||||
|
||||
## 一、原始通达信公式
|
||||
|
||||
```
|
||||
知行短期趋势线:EMA(EMA(C,10),10),COLORE61851,LINETHICK1;
|
||||
MA1:=MA(CLOSE,60);
|
||||
MA2:=EMA(CLOSE,13);
|
||||
Z1:=STRCAT(HYBLOCK,' ');
|
||||
Z2:=STRCAT(Z1,DYBLOCK);
|
||||
Z3:=STRCAT(Z2,' ');
|
||||
DRAWTEXT_FIX(ISLASTBAR,0,0,0,STRCAT(Z3,GNBLOCK)),COLOR00C0C0;
|
||||
知行多空线:(MA(CLOSE,M1)+MA(CLOSE,M2)+MA(CLOSE,M3)+MA(CLOSE,M4))/4;
|
||||
```
|
||||
|
||||
**参数表(通达信公式管理器里配置,公式文本不带——移植时最容易丢的就是这个):**
|
||||
|
||||
| 参数 | 缺省值 |
|
||||
|------|--------|
|
||||
| M1 | 14 |
|
||||
| M2 | 28 |
|
||||
| M3 | 57 |
|
||||
| M4 | 114 |
|
||||
|
||||
## 二、逐行语义
|
||||
|
||||
| 行 | 作用 | 移植处理 |
|
||||
|----|------|----------|
|
||||
| 知行短期趋势线 | EMA 嵌套两层,主图线 | 画线,#E61851 |
|
||||
| MA1 / MA2 | `:=` 隐藏赋值,且未被后续引用 → 死代码 | 不画 |
|
||||
| Z1~Z3 + DRAWTEXT_FIX | 左上角固定文本:行业板块+地域板块+概念板块(通达信本地板块数据) | 无本地板块数据源,用「行业+地域」近似做成图例行;概念板块缺失 |
|
||||
| 知行多空线 | 4 条 MA 的等权平均,主图线 | 画线,周期 14/28/57/114 |
|
||||
|
||||
## 三、数值口径(与通达信逐位一致)
|
||||
|
||||
**EMA(通达信式)**:`E[i] = (2·X[i] + (N−1)·E[i−1]) / (N+1)`,首根以自身为种子
|
||||
(`E[0] = X[0]`)。等价于系数 `k = 2/(N+1)` 的 `E[i] = k·X[i] + (1−k)·E[i−1]`。
|
||||
无限记忆,但衰减因子 `(N−1)/(N+1)`(N=10 时 ≈0.82/根),截断起点的影响几十根后可忽略。
|
||||
|
||||
**MA(通达信式,严格窗口)**:窗口不满输出空值(null/NaN),**不是** min_periods=1 的渐进均值——
|
||||
很多图表库内置 MA 是渐进口径,直接用会整条线偏掉。
|
||||
|
||||
**多空线**:`dkx[i] = (MA14[i] + MA28[i] + MA57[i] + MA114[i]) / 4`,四个 MA 任一为空则为空。
|
||||
即前 113 根没有多空线(通达信从上市日起算,同样如此)。
|
||||
|
||||
**复权口径**:序列必须与图表展示用同一复权基准(前复权/不复权)的收盘价计算,否则数值对不上。
|
||||
|
||||
## 四、参考实现(框架无关 TypeScript,可直接拷贝)
|
||||
|
||||
```ts
|
||||
export const DKX_PERIODS = [14, 28, 57, 114];
|
||||
|
||||
function ema(src: number[], n: number): number[] {
|
||||
const out = new Array<number>(src.length);
|
||||
const k = 2 / (n + 1);
|
||||
let prev = NaN;
|
||||
for (let i = 0; i < src.length; i++) {
|
||||
prev = Number.isNaN(prev) ? src[i] : src[i] * k + prev * (1 - k);
|
||||
out[i] = prev;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function sma(src: number[], n: number): (number | null)[] {
|
||||
const out = new Array<number | null>(src.length).fill(null);
|
||||
let sum = 0;
|
||||
for (let i = 0; i < src.length; i++) {
|
||||
sum += src[i];
|
||||
if (i >= n) sum -= src[i - n];
|
||||
if (i >= n - 1) out[i] = sum / n;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** closes 为整段历史收盘价(建议从上市日或至少 ≥ 需求长度+114 根起) */
|
||||
export function computeZhixingSeries(closes: number[]) {
|
||||
const trend = ema(ema(closes, 10), 10);
|
||||
const mas = DKX_PERIODS.map((p) => sma(closes, p));
|
||||
const dkx = new Array<number | null>(closes.length).fill(null);
|
||||
for (let i = 0; i < closes.length; i++) {
|
||||
const m = mas.map((a) => a[i]);
|
||||
if (m.every((v) => v != null)) dkx[i] = m.reduce((s, v) => s + (v as number), 0) / m.length;
|
||||
}
|
||||
return { trend, dkx };
|
||||
}
|
||||
```
|
||||
|
||||
## 五、参考实现(Python / numpy)
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
|
||||
DKX_PERIODS = (14, 28, 57, 114)
|
||||
|
||||
def ema_tdx(x: np.ndarray, n: int) -> np.ndarray:
|
||||
out = np.empty(len(x))
|
||||
k = 2.0 / (n + 1)
|
||||
prev = np.nan
|
||||
for i, v in enumerate(x):
|
||||
prev = v if np.isnan(prev) else v * k + prev * (1 - k)
|
||||
out[i] = prev
|
||||
return out
|
||||
# pandas 等价写法(adjust=False 且首根种子=自身,与通达信一致):
|
||||
# s.ewm(span=n, adjust=False).mean()
|
||||
|
||||
def sma_tdx(x: np.ndarray, n: int) -> np.ndarray:
|
||||
c = np.concatenate(([0.0], np.cumsum(x)))
|
||||
out = np.full(len(x), np.nan)
|
||||
out[n - 1:] = (c[n:] - c[:-n]) / n # 窗口不满保持 NaN
|
||||
return out
|
||||
|
||||
def zhixing(close: np.ndarray):
|
||||
trend = ema_tdx(ema_tdx(close.astype(float), 10), 10)
|
||||
stack = np.vstack([sma_tdx(close.astype(float), p) for p in DKX_PERIODS])
|
||||
dkx = np.full(len(close), np.nan)
|
||||
ok = ~np.isnan(stack).any(axis=0)
|
||||
dkx[ok] = stack[:, ok].mean(axis=0)
|
||||
return trend, dkx
|
||||
```
|
||||
|
||||
## 六、校验向量(移植后跑一遍,全对即口径正确)
|
||||
|
||||
**趋势线** `closes = [10,11,12,13,14,15]`:
|
||||
|
||||
```
|
||||
EMA(C,10) = 10.000000, 10.181818, 10.512397, 10.964688, 11.516563, 12.149915
|
||||
EMA(EMA(C,10),10) = 10.000000, 10.033058, 10.120210, 10.273752, 10.499717, 10.799753
|
||||
```
|
||||
|
||||
**MA 严格窗口** `sma([1,2,3,4,5,6], 3)`:
|
||||
|
||||
```
|
||||
null, null, 2.000000, 3.000000, 4.000000, 5.000000
|
||||
```
|
||||
|
||||
**多空线预热** `closes[i] = i+1`(线性爬坡,116 根):索引 0~112 全为 null;
|
||||
索引 113 起有值,闭式解 `dkx[i] = (i+1) − (13+27+56+113)/8 = i+1 − 26.125`:
|
||||
|
||||
```
|
||||
dkx[113] = 87.875000 dkx[114] = 88.875000 dkx[115] = 89.875000
|
||||
```
|
||||
|
||||
## 七、数据与预热要求
|
||||
|
||||
- MA114 需预热 113 根:**喂给算法的历史长度 = 可视区最左端再往左 ≥113 根**。
|
||||
分页加载的图表不要只算当前窗口(首屏窗口常见 240 根,左边会缺一大段),
|
||||
应在「全部已加载历史」上整段计算,左滑前插后整体重算。
|
||||
- EMA 理论上要上市日起算;实际截断到几百根即可(衰减 0.82/根,60 根后残差 < 1e−5)。
|
||||
- 建议 closes 传入前先按 timestamp 升序、剔除停牌空K。
|
||||
|
||||
## 八、klinecharts v10 集成要点(本仓库方案)
|
||||
|
||||
- 注册:`registerIndicator(makeZhixingIndicator(get))`,模板工厂注入「(key, timestamp) → 预计算值」
|
||||
访问器;序列由 DetailKLine 在 allData 上预计算写入 `PV['zx_trend']/PV['zx_dkx']`,
|
||||
`calc` 里按 bar.timestamp 取值(**不要用图表相对索引**,翻页后会错位)。
|
||||
- 回调参数的 `Indicator<D>` 不带 E 泛型,`extendData` 是 unknown,取值需 `as` 收窄。
|
||||
- `createTooltipDataSource` 的 `legends` 会整体替换默认图例行,线值图例须自己拼回;
|
||||
`calcParams: DKX_PERIODS` 让图例显示「知行(14,28,57,114)」(通达信式)。
|
||||
- 长周期指标 + 分页窗口的完整坑位说明见
|
||||
`memory/custom-indicator-framework.md`。
|
||||
|
||||
## 九、移植检查清单
|
||||
|
||||
1. M1~M4 = **14/28/57/114**(不是 BBI 的 3/6/12/24)
|
||||
2. EMA 首根种子=自身;MA 窗口不满=null(两条都与常见库默认不同)
|
||||
3. 计算输入与显示用同一复权基准的收盘价
|
||||
4. 预热 ≥113 根覆盖到可视区最左端之外
|
||||
5. 跑第六节校验向量,逐位一致
|
||||
6. 颜色:趋势线 #E61851、多空线 #F5C518、板块文本 #00C0C0
|
||||
109
frontend/src/indicators/zhixing.ts
Normal file
109
frontend/src/indicators/zhixing.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
// 通达信《知行》主图指标前端移植
|
||||
//
|
||||
// 知行短期趋势线:EMA(EMA(C,10),10),COLORE61851,LINETHICK1;
|
||||
// 知行多空线:(MA(CLOSE,M1)+MA(CLOSE,M2)+MA(CLOSE,M3)+MA(CLOSE,M4))/4;
|
||||
//
|
||||
// - M1~M4 = 14/28/57/114(用户通达信公式参数表里的缺省值,公式文本不带)
|
||||
// - 原文 MA1:=MA(CLOSE,60) / MA2:=EMA(CLOSE,13) 为隐藏赋值(:=)且未被引用,不绘制
|
||||
// - DRAWTEXT_FIX 的 HYBLOCK/DYBLOCK/GNBLOCK 是通达信本地板块数据;web 端用后端
|
||||
// info 的 行业+地域 近似前两者(经 extendData 注入图例行),概念板块无数据源暂缺
|
||||
//
|
||||
// 序列不是在图表窗口上现算,而是由 DetailKLine 在 allData(全部已加载历史)上预计算、
|
||||
// 经 PV 按时间戳取值(与 pv-boll 同款管道):MA114 预热 113 根,图表首吐窗口 240 根,
|
||||
// 窗口现算左边会缺一大段;allData 首屏 500 根(左滑翻页还会前插)足够覆盖。
|
||||
import type { IndicatorTemplate, IndicatorTooltipData } from 'klinecharts';
|
||||
|
||||
export const ZHIXING_NAME = 'pv-zhixing';
|
||||
/** 多空线 4 个 MA 周期(M1~M4,通达信参数表缺省值) */
|
||||
export const DKX_PERIODS = [14, 28, 57, 114];
|
||||
/** 板块文本颜色(通达信原文 COLOR00C0C0) */
|
||||
export const ZHIXING_BLOCK_COLOR = '#00C0C0';
|
||||
/** 趋势线颜色(通达信原文 COLORE61851,同时用作开关按钮主色) */
|
||||
export const ZHIXING_TREND_COLOR = '#E61851';
|
||||
export const ZHIXING_DKX_COLOR = '#F5C518';
|
||||
|
||||
export interface ZhixingRow { trend?: number; dkx?: number }
|
||||
export interface ZhixingExt { blocks?: string }
|
||||
|
||||
/** 序列取值函数:(指标 key, 时间戳) → 值(DetailKLine 的 g() 按时间戳定位 allData 索引) */
|
||||
export type ZhixingGetter = (key: 'zx_trend' | 'zx_dkx', ts: number) => number | undefined;
|
||||
|
||||
/** 通达信 EMA:E=(2*X+(N-1)*prev)/(N+1),首根以自身为种子。无限记忆,但衰减因子
|
||||
* (N-1)/(N+1)≈0.82/根,allData 截断的影响几十根后即可忽略,左滑前插会整体重算自愈 */
|
||||
function ema(src: number[], n: number): number[] {
|
||||
const out = new Array<number>(src.length);
|
||||
const k = 2 / (n + 1);
|
||||
let prev = NaN;
|
||||
for (let i = 0; i < src.length; i++) {
|
||||
prev = Number.isNaN(prev) ? src[i] : src[i] * k + prev * (1 - k);
|
||||
out[i] = prev;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** 通达信 MA:窗口不满为 null(忠实原公式;主图 MA 指标是 min_periods=1,口径不同) */
|
||||
function sma(src: number[], n: number): (number | null)[] {
|
||||
const out = new Array<number | null>(src.length).fill(null);
|
||||
let sum = 0;
|
||||
for (let i = 0; i < src.length; i++) {
|
||||
sum += src[i];
|
||||
if (i >= n) sum -= src[i - n];
|
||||
if (i >= n - 1) out[i] = sum / n;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** 在整段已加载历史上计算知行序列(与 allData 按索引对齐),build / 左滑前插后各跑一次 */
|
||||
export function computeZhixingSeries(closes: number[]): { trend: (number | null)[]; dkx: (number | null)[] } {
|
||||
const trend = ema(ema(closes, 10), 10);
|
||||
const mas = DKX_PERIODS.map((p) => sma(closes, p));
|
||||
const dkx = new Array<number | null>(closes.length).fill(null);
|
||||
for (let i = 0; i < closes.length; i++) {
|
||||
const m = mas.map((a) => a[i]);
|
||||
if (m.every((v) => v != null)) dkx[i] = m.reduce((s, v) => s + (v as number), 0) / m.length;
|
||||
}
|
||||
return { trend, dkx };
|
||||
}
|
||||
|
||||
/** 指标模板工厂:注册时注入按时间戳取预计算序列的访问器(实例级 g 闭包,随每次
|
||||
* DetailKLine 挂载重注册换绑,与 pv-boll 同款;幂等注册会绑死首挂实例导致切股错线) */
|
||||
export function makeZhixingIndicator(get: ZhixingGetter): IndicatorTemplate<ZhixingRow, unknown, ZhixingExt> {
|
||||
return {
|
||||
name: ZHIXING_NAME,
|
||||
shortName: '知行',
|
||||
figures: [
|
||||
{ key: 'trend', title: '趋势线', type: 'line', styles: () => ({ color: ZHIXING_TREND_COLOR }) },
|
||||
{ key: 'dkx', title: '多空线', type: 'line', styles: () => ({ color: ZHIXING_DKX_COLOR }) },
|
||||
],
|
||||
calc: (d) => d.map((bar) => {
|
||||
const row: ZhixingRow = {};
|
||||
const t = get('zx_trend', bar.timestamp);
|
||||
const k = get('zx_dkx', bar.timestamp);
|
||||
if (t != null) row.trend = t;
|
||||
if (k != null) row.dkx = k;
|
||||
return row;
|
||||
}),
|
||||
// 通达信 DRAWTEXT_FIX(ISLASTBAR,0,0,0,STRCAT(HYBLOCK,DYBLOCK,GNBLOCK)) 的近似:
|
||||
// 自定义 legends 会整体替换图例行,须把两条线的值一并补回(颜色随各自线色)。
|
||||
// calcParamsText 从 calcParams 拼,保留「知行(14,28,57,114)」的通达信式图例
|
||||
createTooltipDataSource: ({ indicator, crosshair }): IndicatorTooltipData => {
|
||||
const di = crosshair.dataIndex;
|
||||
const row = (typeof di === 'number' && di >= 0 ? indicator.result[di] : undefined) ?? {};
|
||||
const fmt = (v?: number) => (v == null ? '—' : v.toFixed(2));
|
||||
const legends: IndicatorTooltipData['legends'] = [];
|
||||
// 回调参数的 Indicator<D> 未带 E 泛型(extendData 为 unknown),需收窄
|
||||
const blocks = (indicator.extendData as ZhixingExt | undefined)?.blocks;
|
||||
if (blocks) {
|
||||
legends.push({ title: { text: '板块', color: '#9AA0AA' }, value: { text: blocks, color: ZHIXING_BLOCK_COLOR } });
|
||||
}
|
||||
legends.push({ title: { text: '趋势线', color: ZHIXING_TREND_COLOR }, value: { text: fmt(row.trend), color: ZHIXING_TREND_COLOR } });
|
||||
legends.push({ title: { text: '多空线', color: ZHIXING_DKX_COLOR }, value: { text: fmt(row.dkx), color: ZHIXING_DKX_COLOR } });
|
||||
return {
|
||||
name: '知行',
|
||||
calcParamsText: `(${(indicator.calcParams as number[]).join(',')})`,
|
||||
legends,
|
||||
features: [],
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
9
frontend_dev.log
Normal file
9
frontend_dev.log
Normal file
@@ -0,0 +1,9 @@
|
||||
$ vite
|
||||
|
||||
[32m[1mVITE[22m v6.4.3[39m [2mready in [0m[1m598[22m[2m[0m ms[22m
|
||||
|
||||
[32m➜[39m [1mLocal[22m: [36mhttp://localhost:[1m5173[22m/[39m
|
||||
[2m [32m➜[39m [1mNetwork[22m[2m: use [22m[1m--host[22m[2m to expose[22m
|
||||
[2m00:44:18[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/style.css, /@fs/D:\Project\stock\frontend\src\components\DetailKLine.vue[22m
|
||||
[2m00:44:23[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/@fs/D:\Project\stock\frontend\src\components\DetailKLine.vue, /src/style.css[22m
|
||||
[2m00:44:24[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/style.css, /@fs/D:\Project\stock\frontend\src\components\DetailKLine.vue[22m
|
||||
Reference in New Issue
Block a user