dragon-quant 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. dragon_quant-0.1.0/LICENSE +21 -0
  2. dragon_quant-0.1.0/PKG-INFO +520 -0
  3. dragon_quant-0.1.0/README.md +502 -0
  4. dragon_quant-0.1.0/dragon_quant/__init__.py +17 -0
  5. dragon_quant-0.1.0/dragon_quant/__main__.py +5 -0
  6. dragon_quant-0.1.0/dragon_quant/analyze.py +113 -0
  7. dragon_quant-0.1.0/dragon_quant/cache/__init__.py +0 -0
  8. dragon_quant-0.1.0/dragon_quant/cache/data_cache.py +171 -0
  9. dragon_quant-0.1.0/dragon_quant/cli.py +301 -0
  10. dragon_quant-0.1.0/dragon_quant/data.py +222 -0
  11. dragon_quant-0.1.0/dragon_quant/logging/__init__.py +2 -0
  12. dragon_quant-0.1.0/dragon_quant/logging/logger.py +189 -0
  13. dragon_quant-0.1.0/dragon_quant/logging/query.py +236 -0
  14. dragon_quant-0.1.0/dragon_quant/logging/reporter.py +331 -0
  15. dragon_quant-0.1.0/dragon_quant/models/__init__.py +0 -0
  16. dragon_quant-0.1.0/dragon_quant/models/types.py +88 -0
  17. dragon_quant-0.1.0/dragon_quant/orchestrator.py +476 -0
  18. dragon_quant-0.1.0/dragon_quant/providers/__init__.py +23 -0
  19. dragon_quant-0.1.0/dragon_quant/providers/base.py +62 -0
  20. dragon_quant-0.1.0/dragon_quant/providers/cookie.py +92 -0
  21. dragon_quant-0.1.0/dragon_quant/providers/eastmoney.py +283 -0
  22. dragon_quant-0.1.0/dragon_quant/providers/tencent.py +201 -0
  23. dragon_quant-0.1.0/dragon_quant/providers/xueqiu.py +179 -0
  24. dragon_quant-0.1.0/dragon_quant/rate_limit.py +103 -0
  25. dragon_quant-0.1.0/dragon_quant/scorers/__init__.py +11 -0
  26. dragon_quant-0.1.0/dragon_quant/scorers/absorption.py +297 -0
  27. dragon_quant-0.1.0/dragon_quant/scorers/anti_drop.py +206 -0
  28. dragon_quant-0.1.0/dragon_quant/scorers/drive.py +406 -0
  29. dragon_quant-0.1.0/dragon_quant/scorers/leadership.py +225 -0
  30. dragon_quant-0.1.0/dragon_quant/storage/__init__.py +0 -0
  31. dragon_quant-0.1.0/dragon_quant/storage/manager.py +109 -0
  32. dragon_quant-0.1.0/dragon_quant/storage/paths.py +43 -0
  33. dragon_quant-0.1.0/dragon_quant/utils/__init__.py +0 -0
  34. dragon_quant-0.1.0/dragon_quant.egg-info/PKG-INFO +520 -0
  35. dragon_quant-0.1.0/dragon_quant.egg-info/SOURCES.txt +38 -0
  36. dragon_quant-0.1.0/dragon_quant.egg-info/dependency_links.txt +1 -0
  37. dragon_quant-0.1.0/dragon_quant.egg-info/entry_points.txt +2 -0
  38. dragon_quant-0.1.0/dragon_quant.egg-info/top_level.txt +1 -0
  39. dragon_quant-0.1.0/pyproject.toml +31 -0
  40. dragon_quant-0.1.0/setup.cfg +4 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 gitBingxu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,520 @@
1
+ Metadata-Version: 2.4
2
+ Name: dragon-quant
3
+ Version: 0.1.0
4
+ Summary: 龙头战法四维量化筛选系统 — A股涨停板龙头识别工具
5
+ Author: gitBingxu
6
+ License-Expression: MIT
7
+ Project-URL: repository, https://github.com/gitBingxu/dragon-quant
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Financial and Insurance Industry
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.8
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Topic :: Office/Business :: Financial :: Investment
14
+ Requires-Python: >=3.8
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Dynamic: license-file
18
+
19
+ # dragon-quant 🐉
20
+
21
+ **龙头战法四维量化筛选系统** — A 股涨停板龙头识别工具
22
+
23
+ 基于东方财富、雪球、腾讯三大公开数据源,对涨停候选股进行四维量化评分,自动识别市场龙头。
24
+
25
+ ## 安装
26
+
27
+ ```bash
28
+ pip install dragon-quant
29
+ ```
30
+
31
+ 或从源码安装:
32
+
33
+ ```bash
34
+ git clone https://github.com/gitBingxu/dragon-quant.git
35
+ cd dragon-quant
36
+ pip install -e .
37
+ ```
38
+
39
+ ## 快速开始
40
+
41
+ ```bash
42
+ # 扫榜 — 找 top5 龙头
43
+ dragon-quant scan --top 5
44
+
45
+ # 完整扫榜
46
+ dragon-quant scan --top 25 --candidates 5 --workers 2
47
+ ```
48
+
49
+ ## CLI 命令大全
50
+
51
+ ### `scan` — 扫榜
52
+
53
+ ```bash
54
+ dragon-quant scan [--top 25] [--candidates 5] [--workers 2]
55
+ ```
56
+
57
+ | 参数 | 默认 | 说明 |
58
+ |---|---|---|
59
+ | `--top` | 25 | 最终输出的候选股数量 |
60
+ | `--candidates` | 5 | 每个板块取前 N 只 |
61
+ | `--workers` | 2 | 并发线程数 |
62
+
63
+ 输出包含:板块排行、候选股列表、四维评分表格、自然语言详细报告,同时自动持久化日志和结果到 `~/Library/Application Support/dragon-quant/`。
64
+
65
+ ### `logs` — 日志查询
66
+
67
+ ```bash
68
+ # 查看最近 20 条日志
69
+ dragon-quant logs tail [-n 20]
70
+
71
+ # 按条件查询
72
+ dragon-quant logs query [--date 20260513] [--category scorer:drive] [--level error] [--code 600172]
73
+
74
+ # 查看最新扫描摘要(API 统计、错误数等)
75
+ dragon-quant logs summary
76
+
77
+ # 列出所有日志文件
78
+ dragon-quant logs list
79
+
80
+ # 清除 7 天前的日志
81
+ dragon-quant logs clear --days 7
82
+ ```
83
+
84
+ ### `data` — 原子数据查询
85
+
86
+ ```bash
87
+ # 板块排行榜
88
+ dragon-quant data sector # 涨幅榜
89
+ dragon-quant data sector --asc # 跌幅榜
90
+
91
+ # 板块成分股
92
+ dragon-quant data components --sector BK0487
93
+
94
+ # 个股日 K 线
95
+ dragon-quant data kline --code 600172 [--source xueqiu] [--days 20]
96
+
97
+ # 个股 1 分钟 K 线(分时)
98
+ dragon-quant data minute --code 600172
99
+
100
+ # 实时行情
101
+ dragon-quant data quote --code 600172
102
+ dragon-quant data batch-quote --codes 600172,000001,002409
103
+
104
+ # Cookie 管理
105
+ dragon-quant data cookie-status # 查看 Cookie 状态
106
+ dragon-quant data cookie-fetch # 刷新全部 Cookie
107
+ dragon-quant data cookie-fetch --source xueqiu # 只刷新雪球
108
+ ```
109
+
110
+ ### `storage` — 数据管理
111
+
112
+ ```bash
113
+ dragon-quant storage status # 查看存储状态
114
+ dragon-quant storage size # 磁盘占用
115
+ dragon-quant storage clear --all # 清理全部数据
116
+ dragon-quant storage clear --logs --days 3 # 清理 3 天前的日志
117
+ ```
118
+
119
+ ## Programmtic API
120
+
121
+ ### 编排器 — 完整扫描
122
+
123
+ ```python
124
+ import dragon_quant
125
+
126
+ result = dragon_quant.scan(top_n=5, candidates_n=5, workers=2)
127
+ # 返回 dict:
128
+ # {
129
+ # "timestamp": "20260513_160000",
130
+ # "elapsed_s": 38.2,
131
+ # "sectors": {"up": [...], "down": [...]},
132
+ # "ranking": [
133
+ # {
134
+ # "code": "600172", "name": "黄河旋风",
135
+ # "concepts": ["培育钻石"], "board_count": 3,
136
+ # "composite_score": 71.8,
137
+ # "dimensions": {
138
+ # "drive": {"score": 99.0, "weight": 0.35, "details": {...}},
139
+ # "anti_drop": {"score": 61.0, "weight": 0.15, "details": {...}},
140
+ # "leadership": {"score": 50.0, "weight": 0.25, "details": {...}},
141
+ # "absorption": {"score": 62.0, "weight": 0.25, "details": {...}},
142
+ # }
143
+ # },
144
+ # ...
145
+ # ],
146
+ # "api_stats": {...},
147
+ # "report_text": "黄河旋风(600172)——培育钻石——3连板-71.8分-强票\n..."
148
+ # }
149
+ ```
150
+
151
+ ### 原子数据查询
152
+
153
+ ```python
154
+ from dragon_quant.data import (
155
+ get_sector_ranking, get_sector_components, get_sector_5min_kline,
156
+ get_kline, get_minute_kline, get_quote, batch_get_quotes,
157
+ cookie_status, fetch_cookies,
158
+ )
159
+
160
+ # 板块
161
+ sectors = get_sector_ranking() # 涨幅榜
162
+ stocks = get_sector_components("BK0487") # 成分股
163
+ skline = get_sector_5min_kline("BK0487") # 板块 5 分 K
164
+
165
+ # 个股
166
+ kline = get_kline("600172", source="xueqiu", days=30)
167
+ mline = get_minute_kline("600172") # 1 分 K
168
+ quote = get_quote("600172") # 实时行情
169
+ quotes = batch_get_quotes(["600172", "000001", "002409"])
170
+
171
+ # Cookie 管理
172
+ status = cookie_status() # 查看 Cookie 是否有效
173
+ fetch_cookies() # 刷新全部 Cookie
174
+ fetch_cookies(source="xueqiu") # 只刷新雪球 Cookie
175
+ ```
176
+
177
+ ### 日志查询
178
+
179
+ ```python
180
+ from dragon_quant.logging.query import (
181
+ tail_logs, query_logs, clear_logs, list_logs, log_summary,
182
+ )
183
+
184
+ # 最近 20 条
185
+ entries = tail_logs(20)
186
+
187
+ # 按条件查
188
+ errors = query_logs(level="error")
189
+ drive = query_logs(category="scorer:drive", code="600172")
190
+
191
+ # 扫描摘要
192
+ s = log_summary() # {"api_stats": {...}, "error_count": 0, "phases": {...}}
193
+
194
+ # 列出日志文件
195
+ files = list_logs()
196
+
197
+ # 清除 7 天前
198
+ result = clear_logs(days=7) # {"cleared": 3, "kept": 2, "files_removed": [...]}
199
+ ```
200
+
201
+ ## 四维评分体系
202
+
203
+ ### 一、带动性(权重 35%)— "你是带头大哥吗?"
204
+
205
+ 评估这只股票涨停后对同板块其他股票的带动效应。
206
+
207
+ - **板块共鸣(30%)**:同板块涨停股占比
208
+ - **跟风力度(30%)**:同板块非涨停股中涨幅 >3% 的比例
209
+ - **封板决策力(40%)**:封板时间早晚、在板块内的封板排名、小弟跟进紧密度
210
+ - 每多一连板额外 +5 分(封顶 100)
211
+
212
+ ### 二、抗跌性(权重 15%)— "大盘崩了你扛得住吗?"
213
+
214
+ 分析近期大盘跳水日(单日跌幅 < -0.7%)中个股表现。
215
+
216
+ - **相对回撤(40%)**:个股涨跌幅 vs 大盘涨跌幅
217
+ - **日内承接(30%)**:下影线比例 + 收盘位置
218
+ - **反弹弹性(30%)**:次日超额收益
219
+
220
+ ### 三、领涨性(权重 25%)— "平时你在行业里排老几?"
221
+
222
+ 不看涨停日,评估该股在同行业中的日常排名。
223
+
224
+ - **当日真实排名**:在行业成分股中的确切分位
225
+ - **历史估算排名**:近 5 个非涨停日的正态分布近似排位
226
+ - 偏离度加成:比行业中位数高出几个标准差
227
+
228
+ ### 四、资金承接性(权重 25%)— "钱从别的板块跑你这来了吗?"
229
+
230
+ 检测市场恐慌时跨板块的资金虹吸效应。
231
+
232
+ - 多板块 5 分 K 滑动窗口检测(≥2 个板块跌 >1% & 目标板块涨 >0.3%)
233
+ - **虹吸强度(40%)**:板块涨幅 / 窗口振幅
234
+ - **广度(20%)**:被抽血的板块数量
235
+ - **持续性(40%)**:尾盘回撤控制
236
+
237
+ ## 数据源
238
+
239
+ | 数据源 | 用途 | 接口数 |
240
+ |---|---|---|
241
+ | 东方财富 | 板块排行、成分股、板块 5 分 K | 3 |
242
+ | 雪球 | 日 K 线、1 分 K 线 | 2 |
243
+ | 腾讯 | 实时行情、批量行情 | 2 |
244
+
245
+ ## 设计思想
246
+
247
+ ### 分层架构
248
+
249
+ ```
250
+ ┌─────────────────────────────────┐
251
+ │ CLI / Programmtic API │ ← cli.py / __init__.py
252
+ ├─────────────────────────────────┤
253
+ │ Orchestrator(编排器) │ ← Phase A→F 全流程
254
+ ├──────────┬──────────────────────┤
255
+ │ Scorers │ Logger & Reporter │ ← 四维评分 / 结构化日志
256
+ ├──────────┴──────────────────────┤
257
+ │ DataCache + RateLimiter │ ← 内存/本地双缓存 + 限流
258
+ ├─────────────────────────────────┤
259
+ │ Provider 适配层 │ ← 东财 / 雪球 / 腾讯
260
+ └─────────────────────────────────┘
261
+ ```
262
+
263
+ ### 核心设计原则
264
+
265
+ 1. **Provider 抽象**:所有数据源实现 `StockProvider` 接口,评分器只依赖接口不依赖具体实现,可无缝切换/新增数据源
266
+ 2. **并发与限流**:`RateLimiter` 按 `(provider, endpoint)` 维度串行,不同 key 并发,控制 API 请求频率
267
+ 3. **结构化日志**:`ScanLogger` 全链路打点,记录每次 API 调用、每项评分、每个阶段。支持按类别/级别/股票代码查询,方便排查问题
268
+ 4. **结果持久化**:每次扫描自动保存 JSONL 日志、JSON 结果、文本报告三份文件,保留最新快照供 Agent 随时读取
269
+ 5. **懒加载 Provider**:`data.py` 中 Provider 单例延迟初始化,模块 import 不触发网络请求
270
+
271
+ ## 目录结构
272
+
273
+ ```
274
+ dragon_quant/
275
+ ├── __init__.py # 公共 API 导出
276
+ ├── __main__.py # python -m 入口
277
+ ├── cli.py # CLI 命令(scan/logs/data/storage)
278
+ ├── orchestrator.py # 编排器(Phase A→F)
279
+ ├── data.py # 原子数据查询 API
280
+ ├── providers/ # 数据源适配器
281
+ │ ├── base.py # StockProvider 抽象接口
282
+ │ ├── eastmoney.py # 东方财富
283
+ │ ├── xueqiu.py # 雪球
284
+ │ ├── tencent.py # 腾讯
285
+ │ └── cookie.py # Cookie 管理
286
+ ├── scorers/ # 四维评分器
287
+ │ ├── drive.py # 带动性
288
+ │ ├── anti_drop.py # 抗跌性
289
+ │ ├── leadership.py # 领涨性
290
+ │ └── absorption.py # 资金承接
291
+ ├── models/
292
+ │ └── types.py # 数据模型(KBar, Quote, ScoreResult...)
293
+ ├── cache/
294
+ │ └── data_cache.py # 内存+本地双缓存
295
+ ├── logging/
296
+ │ ├── logger.py # ScanLogger 结构化日志
297
+ │ ├── reporter.py # ReportBuilder 自然语言报告
298
+ │ └── query.py # 日志查询 API
299
+ ├── storage/
300
+ │ ├── paths.py # 数据目录管理
301
+ │ └── manager.py # StorageManager
302
+ ├── rate_limit.py # 并发限流器
303
+ └── utils/
304
+ └── __init__.py
305
+ ```
306
+
307
+ ## Agent 集成指南
308
+
309
+ 本节展示 AI Agent 如何通过 Python API 调用 dragon-quant 完成常见任务。
310
+
311
+ ### 场景 1:今日龙头扫榜 + 输出报告
312
+
313
+ ```python
314
+ import dragon_quant
315
+
316
+ # 扫榜取 top5
317
+ result = dragon_quant.scan(top_n=5, candidates_n=5, workers=2)
318
+
319
+ print(f"🐉 今日龙头 TOP5 | 耗时 {result['elapsed_s']}s")
320
+ print()
321
+ print(f"{'排名':4s} {'代码':8s} {'名称':8s} {'综合':>6s} {'带动':>6s} {'抗跌':>6s} {'领涨':>6s} {'承接':>6s}")
322
+ print("-" * 56)
323
+ for i, r in enumerate(result["ranking"], 1):
324
+ dims = r.get("dimensions", {})
325
+ print(f"{i:4d} {r['code']:8s} {r['name']:8s} "
326
+ f"{r['composite_score']:6.1f} "
327
+ f"{dims.get('drive',{}).get('score',0):6.1f} "
328
+ f"{dims.get('anti_drop',{}).get('score',0):6.1f} "
329
+ f"{dims.get('leadership',{}).get('score',0):6.1f} "
330
+ f"{dims.get('absorption',{}).get('score',0):6.1f}")
331
+
332
+ # 输出自然语言报告(可直接发给用户)
333
+ print()
334
+ print(result["report_text"])
335
+ ```
336
+
337
+ ### 场景 2:只取龙头排行数据,不打印(Agent 内部消费)
338
+
339
+ ```python
340
+ import dragon_quant
341
+
342
+ result = dragon_quant.scan(top_n=10, verbose=False)
343
+
344
+ # 提取关键信息
345
+ for r in result["ranking"]:
346
+ code = r["code"]
347
+ name = r["name"]
348
+ score = r["composite_score"]
349
+ concepts = r.get("concepts", [])
350
+ boards = r.get("board_count", 0)
351
+ # 判断等级
352
+ if score >= 80:
353
+ grade = "🐲 龙头"
354
+ elif score >= 65:
355
+ grade = "🔥 强票"
356
+ else:
357
+ grade = "📊 一般"
358
+ print(f"{grade} {code} {name} | {boards}连板 | {', '.join(concepts)} | 综合{score}")
359
+ ```
360
+
361
+ ### 场景 3:查某只股票的 K 线和实时行情
362
+
363
+ ```python
364
+ from dragon_quant.data import get_kline, get_minute_kline, get_quote
365
+
366
+ code = "600172"
367
+
368
+ # 日K线
369
+ kline = get_kline(code, days=30)
370
+ print(f"{code} 最近 30 日 K 线:")
371
+ for k in kline[-5:]: # 最近5天
372
+ print(f" {getattr(k, 'time', '?')} | "
373
+ f"开{getattr(k, 'open', 0):.2f} 收{getattr(k, 'close', 0):.2f} "
374
+ f"涨{getattr(k, 'pct', 0):.2f}%")
375
+
376
+ # 实时行情
377
+ quote = get_quote(code)
378
+ if quote:
379
+ print(f"当前价: {quote.price} | 涨跌幅: {quote.pct}% | 换手率: {getattr(quote, 'turnover', 0):.2f}%")
380
+ ```
381
+
382
+ ### 场景 4:API 返回 400/空数据 → 刷新 Cookie
383
+
384
+ 当 scan() 或数据查询返回 400 错误、空数据时,通常是 Cookie 过期了。刷新后重试即可。
385
+
386
+ ```python
387
+ from dragon_quant.data import cookie_status, fetch_cookies
388
+
389
+ # 先查看状态
390
+ status = cookie_status()
391
+ for source, info in status.items():
392
+ print(f"{source}: {'✅ 有效' if info['ok'] else '❌ 过期'} ({info['length']}字符)")
393
+
394
+ # 如果东财或雪球过期,刷新
395
+ if not status["eastmoney"]["ok"] or not status["xueqiu"]["ok"]:
396
+ print("Cookie 过期,正在刷新...")
397
+ fetch_cookies()
398
+ # 刷新后重新检查
399
+ new_status = cookie_status()
400
+ for source, info in new_status.items():
401
+ print(f" {source}: {'✅' if info['ok'] else '❌'} ({info['length']}字符)")
402
+
403
+ # 刷新后重试 scan
404
+ import dragon_quant
405
+ result = dragon_quant.scan(top_n=5)
406
+ print(f"扫描成功,{len(result['ranking'])} 只候选")
407
+ ```
408
+
409
+ ### 场景 5:查板块热度(哪个方向最强)
410
+
411
+ ```python
412
+ from dragon_quant.data import get_sector_ranking, get_sector_components
413
+
414
+ # 今日涨幅榜 top5 板块
415
+ sectors = get_sector_ranking(asc=False)[:5]
416
+ print("今日最强板块:")
417
+ for s in sectors:
418
+ print(f" {s.name} ({s.code}) | +{s.pct:.2f}%")
419
+
420
+ # 看龙头板块的涨停分布
421
+ if sectors:
422
+ stocks = get_sector_components(sectors[0].code)
423
+ up_limit = [s for s in stocks if s.pct and s.pct >= 9.9]
424
+ print(f"\n{sectors[0].name} 涨停股 ({len(up_limit)} 只):")
425
+ for s in up_limit:
426
+ print(f" {s.code} {s.name} | +{s.pct:.2f}%")
427
+ ```
428
+
429
+ ### 场景 6:排查问题 — 查看扫描日志
430
+
431
+ ```python
432
+ from dragon_quant.logging.query import list_logs, tail_logs, query_logs, log_summary, clear_logs
433
+
434
+ # 列出所有日志文件
435
+ files = list_logs()
436
+ print(f"共 {len(files)} 个日志文件")
437
+ for f in files[:5]:
438
+ print(f" {f['name']} | {f['size']} | {f['lines']} 行")
439
+
440
+ # 查看最新扫描的摘要
441
+ summary = log_summary()
442
+ print(f"\n最新扫描: {summary['file']}")
443
+ print(f" 阶段: {list(summary['phases'].keys())}")
444
+ print(f" API 调用: {summary['api_stats']['total']} 次 | 成功 {summary['api_stats']['ok']} | 失败 {summary['api_stats']['error']}")
445
+ print(f" 评分: {summary['scorer_count']} 次")
446
+ print(f" 错误: {summary['error_count']} 条")
447
+
448
+ # 如果有很多错误,查具体原因
449
+ if summary['error_count'] > 0:
450
+ errors = query_logs(level="error", tail=10)
451
+ print(f"\n最近 10 条错误:")
452
+ for e in errors:
453
+ print(f" [{e.get('category', '')}] {e.get('message', '')}")
454
+ if e.get('data', {}).get('exception'):
455
+ print(f" exception: {e['data']['exception'][:120]}")
456
+
457
+ # 查某只股票的评分细节
458
+ entries = query_logs(category="scorer", code="600172")
459
+ for e in entries:
460
+ print(f" {e['category']} → score={e.get('data',{}).get('score',0)}")
461
+ ```
462
+
463
+ ### 场景 7:清理日志
464
+
465
+ ```python
466
+ from dragon_quant.logging.query import clear_logs, list_logs
467
+
468
+ # 清理前
469
+ before = list_logs()
470
+ print(f"清理前: {len(before)} 个日志文件")
471
+
472
+ # 保留最近 3 天
473
+ result = clear_logs(days=3)
474
+ print(f"删除了 {result['cleared']} 个文件 | 保留 {result['kept']} 个")
475
+ for f in result.get("files_removed", []):
476
+ print(f" - {f}")
477
+ ```
478
+
479
+ ### 场景 8:拿上一次扫描结果(无需重新跑)
480
+
481
+ ```python
482
+ import json
483
+ from pathlib import Path
484
+
485
+ # macOS 默认路径
486
+ latest_path = Path.home() / "Library" / "Application Support" / "dragon-quant" / "results" / "latest.json"
487
+
488
+ if latest_path.exists():
489
+ with open(latest_path) as f:
490
+ data = json.load(f)
491
+
492
+ print(f"上次扫描: {data['timestamp']} | 耗时 {data['elapsed_s']}s")
493
+ for r in data["ranking"]:
494
+ print(f" {r['code']} {r['name']} — {r['composite_score']}分 — {r.get('board_count', 0)}连板")
495
+ else:
496
+ print("暂无扫描缓存,运行一次 scan() 即可生成")
497
+ ```
498
+
499
+ ### 场景 9:批量获取多只票的行情对比
500
+
501
+ ```python
502
+ from dragon_quant.data import batch_get_quotes
503
+
504
+ codes = ["600172", "605589", "603052", "603203", "603126"]
505
+ quotes = batch_get_quotes(codes)
506
+
507
+ print(f"{'代码':8s} {'价格':>8s} {'涨跌幅':>8s} {'换手率':>8s} {'量比':>6s}")
508
+ print("-" * 44)
509
+ for q in quotes:
510
+ if q:
511
+ price = getattr(q, 'price', 0)
512
+ pct = getattr(q, 'pct', 0)
513
+ turnover = getattr(q, 'turnover', 0)
514
+ volume_ratio = getattr(q, 'volume_ratio', 0)
515
+ print(f"{q.code:8s} {price:8.2f} {pct:+7.2f}% {turnover:7.2f}% {volume_ratio:6.2f}")
516
+ ```
517
+
518
+ ## License
519
+
520
+ MIT