stock-analyzer-skill 1.1.0 → 1.2.0
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.
- package/CHANGELOG.md +36 -0
- package/README.md +110 -39
- package/data/reports/202506_Stock_Analysis_Summary.md +271 -0
- package/experts/README.md +23 -2
- package/experts/buffett.md +44 -1
- package/experts/chaogu_yangjia.md +50 -0
- package/experts/decide.md +54 -2
- package/experts/duan_yongping.md +45 -0
- package/experts/lynch.md +48 -1
- package/experts/soros.md +43 -0
- package/experts/xu_xiang.md +44 -0
- package/experts/zhao_laoge.md +53 -0
- package/experts/zuoshou_xinyi.md +66 -0
- package/methodology.md +313 -13
- package/package.json +1 -1
- package/scripts/__pycache__/screener.cpython-314.pyc +0 -0
- package/scripts/api/__init__.py +22 -0
- package/scripts/api/__pycache__/__init__.cpython-314.pyc +0 -0
- package/scripts/api/__pycache__/quote_cli.cpython-314.pyc +0 -0
- package/scripts/api/__pycache__/screener_cli.cpython-314.pyc +0 -0
- package/scripts/api/quote_cli.py +106 -0
- package/scripts/api/screener_cli.py +149 -0
- package/scripts/business/__init__.py +15 -0
- package/scripts/business/__pycache__/__init__.cpython-314.pyc +0 -0
- package/scripts/business/__pycache__/screening_service.cpython-314.pyc +0 -0
- package/scripts/business/__pycache__/stock_analysis.cpython-314.pyc +0 -0
- package/scripts/business/screening_service.py +267 -0
- package/scripts/business/stock_analysis.py +183 -0
- package/scripts/common/__init__.py +334 -0
- package/scripts/common/__pycache__/__init__.cpython-314.pyc +0 -0
- package/scripts/common/__pycache__/http.cpython-314.pyc +0 -0
- package/scripts/common/__pycache__/parsers.cpython-314.pyc +0 -0
- package/scripts/common/__pycache__/utils.cpython-314.pyc +0 -0
- package/scripts/common/__pycache__/validators.cpython-314.pyc +0 -0
- package/scripts/common/exceptions/__init__.py +172 -0
- package/scripts/common/exceptions/__pycache__/__init__.cpython-314.pyc +0 -0
- package/scripts/common/http.py +79 -0
- package/scripts/common/metrics.py +92 -0
- package/scripts/common/parsers.py +125 -0
- package/scripts/common/utils.py +195 -0
- package/scripts/common/validators.py +219 -0
- package/scripts/config/__init__.py +24 -0
- package/scripts/config/__pycache__/__init__.cpython-314.pyc +0 -0
- package/scripts/config/__pycache__/loader.cpython-314.pyc +0 -0
- package/scripts/config/data_source.yaml +126 -0
- package/scripts/config/industry_thresholds.yaml +158 -0
- package/scripts/config/limits.yaml +48 -0
- package/scripts/config/loader.py +141 -0
- package/scripts/config/notification.yaml +57 -0
- package/scripts/config/scoring.yaml +159 -0
- package/scripts/data/__pycache__/config.cpython-314.pyc +0 -0
- package/scripts/data/__pycache__/types.cpython-314.pyc +0 -0
- package/scripts/data/config.py +56 -4
- package/scripts/data/portfolio.json +100 -0
- package/scripts/data/portfolio_example.json +66 -11
- package/scripts/data/sector_stocks.json +244 -80
- package/scripts/data/types.py +3 -3
- package/scripts/fetchers/__init__.py +54 -0
- package/scripts/fetchers/__pycache__/__init__.cpython-314.pyc +0 -0
- package/scripts/fetchers/__pycache__/akshare_quote.cpython-314.pyc +0 -0
- package/scripts/fetchers/__pycache__/eastmoney_event.cpython-314.pyc +0 -0
- package/scripts/fetchers/__pycache__/eastmoney_flow.cpython-314.pyc +0 -0
- package/scripts/fetchers/__pycache__/eastmoney_lhb.cpython-314.pyc +0 -0
- package/scripts/fetchers/__pycache__/eastmoney_quote.cpython-314.pyc +0 -0
- package/scripts/fetchers/__pycache__/efinance_quote.cpython-314.pyc +0 -0
- package/scripts/fetchers/__pycache__/sina_quote.cpython-314.pyc +0 -0
- package/scripts/fetchers/__pycache__/tencent_quote.cpython-314.pyc +0 -0
- package/scripts/fetchers/akshare_quote.py +17 -3
- package/scripts/fetchers/eastmoney_event.py +148 -0
- package/scripts/fetchers/eastmoney_flow.py +118 -0
- package/scripts/fetchers/eastmoney_lhb.py +134 -0
- package/scripts/fetchers/eastmoney_quote.py +3 -3
- package/scripts/fetchers/efinance_quote.py +17 -3
- package/scripts/fetchers/sina_quote.py +5 -9
- package/scripts/fetchers/tencent_quote.py +3 -1
- package/scripts/monitor/__init__.py +13 -0
- package/scripts/monitor/__pycache__/__init__.cpython-314.pyc +0 -0
- package/scripts/monitor/__pycache__/manager.cpython-314.pyc +0 -0
- package/scripts/monitor/channels/__init__.py +6 -0
- package/scripts/monitor/channels/__pycache__/__init__.cpython-314.pyc +0 -0
- package/scripts/monitor/channels/__pycache__/bark.cpython-314.pyc +0 -0
- package/scripts/monitor/channels/__pycache__/base.cpython-314.pyc +0 -0
- package/scripts/monitor/channels/bark.py +75 -0
- package/scripts/monitor/channels/base.py +36 -0
- package/scripts/monitor/health.py +148 -0
- package/scripts/monitor/manager.py +229 -0
- package/scripts/portfolio/__init__.py +13 -0
- package/scripts/portfolio/__pycache__/__init__.cpython-314.pyc +0 -0
- package/scripts/portfolio/__pycache__/manager.cpython-314.pyc +0 -0
- package/scripts/portfolio/manager.py +329 -0
- package/scripts/portfolio/performance.py +209 -0
- package/scripts/screener.py +78 -23
- package/scripts/strategies/factors/__pycache__/liquidity.cpython-314.pyc +0 -0
- package/scripts/strategies/factors/liquidity.py +1 -1
- package/skills/backtest/SKILL.md +57 -0
- package/skills/help/SKILL.md +69 -5
- package/skills/monitor/SKILL.md +98 -0
- package/skills/portfolio/SKILL.md +135 -40
- package/skills/stock/SKILL.md +99 -1
- package/skills/{init → stock-init}/SKILL.md +5 -5
- package/workflow.md +36 -2
- package/scripts/common.py +0 -507
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# 行业差异化财务阈值
|
|
2
|
+
|
|
3
|
+
thresholds:
|
|
4
|
+
银行:
|
|
5
|
+
pe_undervalued: 8
|
|
6
|
+
pe_reasonable: 12
|
|
7
|
+
pe_expensive: 18
|
|
8
|
+
peg_undervalued: 0.5
|
|
9
|
+
peg_reasonable: 1.0
|
|
10
|
+
roe_excellent: 12
|
|
11
|
+
gross_margin_min: 30
|
|
12
|
+
debt_ratio_max: 90
|
|
13
|
+
profit_growth_excellent: 10
|
|
14
|
+
revenue_growth_excellent: 5
|
|
15
|
+
|
|
16
|
+
券商:
|
|
17
|
+
pe_undervalued: 15
|
|
18
|
+
pe_reasonable: 25
|
|
19
|
+
pe_expensive: 35
|
|
20
|
+
peg_undervalued: 0.8
|
|
21
|
+
peg_reasonable: 1.5
|
|
22
|
+
roe_excellent: 10
|
|
23
|
+
gross_margin_min: 25
|
|
24
|
+
debt_ratio_max: 80
|
|
25
|
+
profit_growth_excellent: 15
|
|
26
|
+
revenue_growth_excellent: 10
|
|
27
|
+
|
|
28
|
+
地产:
|
|
29
|
+
pe_undervalued: 6
|
|
30
|
+
pe_reasonable: 10
|
|
31
|
+
pe_expensive: 15
|
|
32
|
+
peg_undervalued: 0.4
|
|
33
|
+
peg_reasonable: 0.8
|
|
34
|
+
roe_excellent: 10
|
|
35
|
+
gross_margin_min: 20
|
|
36
|
+
debt_ratio_max: 85
|
|
37
|
+
profit_growth_excellent: 8
|
|
38
|
+
revenue_growth_excellent: 10
|
|
39
|
+
|
|
40
|
+
医药:
|
|
41
|
+
pe_undervalued: 25
|
|
42
|
+
pe_reasonable: 40
|
|
43
|
+
pe_expensive: 60
|
|
44
|
+
peg_undervalued: 1.0
|
|
45
|
+
peg_reasonable: 2.0
|
|
46
|
+
roe_excellent: 18
|
|
47
|
+
gross_margin_min: 50
|
|
48
|
+
debt_ratio_max: 60
|
|
49
|
+
profit_growth_excellent: 25
|
|
50
|
+
revenue_growth_excellent: 20
|
|
51
|
+
|
|
52
|
+
半导体:
|
|
53
|
+
pe_undervalued: 30
|
|
54
|
+
pe_reasonable: 50
|
|
55
|
+
pe_expensive: 80
|
|
56
|
+
peg_undervalued: 1.0
|
|
57
|
+
peg_reasonable: 2.0
|
|
58
|
+
roe_excellent: 15
|
|
59
|
+
gross_margin_min: 40
|
|
60
|
+
debt_ratio_max: 70
|
|
61
|
+
profit_growth_excellent: 30
|
|
62
|
+
revenue_growth_excellent: 25
|
|
63
|
+
|
|
64
|
+
软件:
|
|
65
|
+
pe_undervalued: 35
|
|
66
|
+
pe_reasonable: 55
|
|
67
|
+
pe_expensive: 90
|
|
68
|
+
peg_undervalued: 1.2
|
|
69
|
+
peg_reasonable: 2.5
|
|
70
|
+
roe_excellent: 15
|
|
71
|
+
gross_margin_min: 45
|
|
72
|
+
debt_ratio_max: 65
|
|
73
|
+
profit_growth_excellent: 35
|
|
74
|
+
revenue_growth_excellent: 30
|
|
75
|
+
|
|
76
|
+
消费:
|
|
77
|
+
pe_undervalued: 20
|
|
78
|
+
pe_reasonable: 30
|
|
79
|
+
pe_expensive: 45
|
|
80
|
+
peg_undervalued: 0.8
|
|
81
|
+
peg_reasonable: 1.5
|
|
82
|
+
roe_excellent: 20
|
|
83
|
+
gross_margin_min: 35
|
|
84
|
+
debt_ratio_max: 60
|
|
85
|
+
profit_growth_excellent: 20
|
|
86
|
+
revenue_growth_excellent: 15
|
|
87
|
+
|
|
88
|
+
能源:
|
|
89
|
+
pe_undervalued: 10
|
|
90
|
+
pe_reasonable: 18
|
|
91
|
+
pe_expensive: 25
|
|
92
|
+
peg_undervalued: 0.5
|
|
93
|
+
peg_reasonable: 1.0
|
|
94
|
+
roe_excellent: 12
|
|
95
|
+
gross_margin_min: 15
|
|
96
|
+
debt_ratio_max: 70
|
|
97
|
+
profit_growth_excellent: 15
|
|
98
|
+
revenue_growth_excellent: 10
|
|
99
|
+
|
|
100
|
+
周期:
|
|
101
|
+
pe_undervalued: 12
|
|
102
|
+
pe_reasonable: 20
|
|
103
|
+
pe_expensive: 30
|
|
104
|
+
peg_undervalued: 0.6
|
|
105
|
+
peg_reasonable: 1.2
|
|
106
|
+
roe_excellent: 15
|
|
107
|
+
gross_margin_min: 15
|
|
108
|
+
debt_ratio_max: 70
|
|
109
|
+
profit_growth_excellent: 25
|
|
110
|
+
revenue_growth_excellent: 20
|
|
111
|
+
|
|
112
|
+
制造:
|
|
113
|
+
pe_undervalued: 18
|
|
114
|
+
pe_reasonable: 28
|
|
115
|
+
pe_expensive: 40
|
|
116
|
+
peg_undervalued: 0.8
|
|
117
|
+
peg_reasonable: 1.5
|
|
118
|
+
roe_excellent: 15
|
|
119
|
+
gross_margin_min: 20
|
|
120
|
+
debt_ratio_max: 65
|
|
121
|
+
profit_growth_excellent: 25
|
|
122
|
+
revenue_growth_excellent: 20
|
|
123
|
+
|
|
124
|
+
军工:
|
|
125
|
+
pe_undervalued: 50
|
|
126
|
+
pe_reasonable: 70
|
|
127
|
+
pe_expensive: 100
|
|
128
|
+
peg_undervalued: 1.5
|
|
129
|
+
peg_reasonable: 2.5
|
|
130
|
+
roe_excellent: 12
|
|
131
|
+
gross_margin_min: 30
|
|
132
|
+
debt_ratio_max: 70
|
|
133
|
+
profit_growth_excellent: 20
|
|
134
|
+
revenue_growth_excellent: 15
|
|
135
|
+
|
|
136
|
+
科技:
|
|
137
|
+
pe_undervalued: 30
|
|
138
|
+
pe_reasonable: 50
|
|
139
|
+
pe_expensive: 80
|
|
140
|
+
peg_undervalued: 1.0
|
|
141
|
+
peg_reasonable: 2.0
|
|
142
|
+
roe_excellent: 15
|
|
143
|
+
gross_margin_min: 40
|
|
144
|
+
debt_ratio_max: 70
|
|
145
|
+
profit_growth_excellent: 30
|
|
146
|
+
revenue_growth_excellent: 25
|
|
147
|
+
|
|
148
|
+
默认:
|
|
149
|
+
pe_undervalued: 15
|
|
150
|
+
pe_reasonable: 25
|
|
151
|
+
pe_expensive: 40
|
|
152
|
+
peg_undervalued: 0.8
|
|
153
|
+
peg_reasonable: 1.5
|
|
154
|
+
roe_excellent: 20
|
|
155
|
+
gross_margin_min: 20
|
|
156
|
+
debt_ratio_max: 60
|
|
157
|
+
profit_growth_excellent: 40
|
|
158
|
+
revenue_growth_excellent: 30
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# A 股市场限制配置
|
|
2
|
+
|
|
3
|
+
# 涨跌停限制 (%)
|
|
4
|
+
board_limits:
|
|
5
|
+
主板: 9.5
|
|
6
|
+
创业板: 19.5
|
|
7
|
+
科创板: 19.5
|
|
8
|
+
北交所: 29.5
|
|
9
|
+
|
|
10
|
+
# 最低市值要求 (亿元)
|
|
11
|
+
min_total_cap:
|
|
12
|
+
主板: 40
|
|
13
|
+
创业板: 20
|
|
14
|
+
科创板: 20
|
|
15
|
+
北交所: 10
|
|
16
|
+
|
|
17
|
+
# 最低成交额要求 (万元)
|
|
18
|
+
min_amount:
|
|
19
|
+
主板: 5000
|
|
20
|
+
创业板: 3000
|
|
21
|
+
科创板: 3000
|
|
22
|
+
北交所: 1000
|
|
23
|
+
|
|
24
|
+
# 退市风险市值 (亿元)
|
|
25
|
+
min_survival_cap:
|
|
26
|
+
主板: 3
|
|
27
|
+
创业板: 2
|
|
28
|
+
科创板: 2
|
|
29
|
+
北交所: 1
|
|
30
|
+
|
|
31
|
+
# ST 风险检测 (名称前缀)
|
|
32
|
+
st_prefixes:
|
|
33
|
+
- "ST"
|
|
34
|
+
- "*ST"
|
|
35
|
+
- "S*ST"
|
|
36
|
+
- "SST"
|
|
37
|
+
|
|
38
|
+
# 商誉减值风险阈值 (%)
|
|
39
|
+
goodwill_ratio_warning: 30
|
|
40
|
+
goodwill_ratio_danger: 50
|
|
41
|
+
|
|
42
|
+
# 股权质押风险阈值 (%)
|
|
43
|
+
pledge_ratio_warning: 70
|
|
44
|
+
pledge_ratio_danger: 85
|
|
45
|
+
|
|
46
|
+
# 连续亏损检测
|
|
47
|
+
loss_years_warning: 2
|
|
48
|
+
loss_years_danger: 3
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"""
|
|
2
|
+
配置加载器,支持 YAML 配置文件。
|
|
3
|
+
|
|
4
|
+
配置文件目录: scripts/config/
|
|
5
|
+
配置文件:
|
|
6
|
+
- scoring.yaml: 评分配置
|
|
7
|
+
- limits.yaml: 涨跌停/市值限制配置
|
|
8
|
+
- data_source.yaml: 数据源配置
|
|
9
|
+
- industry_thresholds.yaml: 行业差异化阈值
|
|
10
|
+
"""
|
|
11
|
+
import yaml
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Any, Optional
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ConfigLoader:
|
|
17
|
+
"""配置加载器,支持 YAML 配置文件(带缓存)。"""
|
|
18
|
+
|
|
19
|
+
_cache: dict = {}
|
|
20
|
+
_config_dir: Path = Path(__file__).parent
|
|
21
|
+
|
|
22
|
+
@classmethod
|
|
23
|
+
def load(cls, filename: str, use_cache: bool = True) -> dict:
|
|
24
|
+
"""
|
|
25
|
+
加载配置文件。
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
filename: 配置文件名 (如 "scoring.yaml")
|
|
29
|
+
use_cache: 是否使用缓存
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
配置字典
|
|
33
|
+
"""
|
|
34
|
+
if use_cache and filename in cls._cache:
|
|
35
|
+
return cls._cache[filename]
|
|
36
|
+
|
|
37
|
+
config_path = cls._config_dir / filename
|
|
38
|
+
if not config_path.exists():
|
|
39
|
+
return {}
|
|
40
|
+
|
|
41
|
+
with open(config_path, "r", encoding="utf-8") as f:
|
|
42
|
+
config = yaml.safe_load(f) or {}
|
|
43
|
+
|
|
44
|
+
cls._cache[filename] = config
|
|
45
|
+
return config
|
|
46
|
+
|
|
47
|
+
@classmethod
|
|
48
|
+
def get(cls, filename: str, key_path: str, default: Any = None) -> Any:
|
|
49
|
+
"""
|
|
50
|
+
获取配置值,支持嵌套键路径。
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
filename: 配置文件名
|
|
54
|
+
key_path: 键路径,如 "alignment_scores.多头排列"
|
|
55
|
+
default: 默认值
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
配置值
|
|
59
|
+
"""
|
|
60
|
+
config = cls.load(filename)
|
|
61
|
+
keys = key_path.split(".")
|
|
62
|
+
|
|
63
|
+
value = config
|
|
64
|
+
for key in keys:
|
|
65
|
+
if isinstance(value, dict):
|
|
66
|
+
value = value.get(key)
|
|
67
|
+
else:
|
|
68
|
+
return default
|
|
69
|
+
|
|
70
|
+
return value if value is not None else default
|
|
71
|
+
|
|
72
|
+
@classmethod
|
|
73
|
+
def reload(cls, filename: str = None):
|
|
74
|
+
"""重新加载配置。"""
|
|
75
|
+
if filename:
|
|
76
|
+
cls._cache.pop(filename, None)
|
|
77
|
+
else:
|
|
78
|
+
cls._cache.clear()
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def get_scoring_config(key: str = None, default: Any = None) -> Any:
|
|
82
|
+
"""
|
|
83
|
+
获取评分配置。
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
key: 键路径(如 "alignment_scores.多头排列"),为空时返回整个配置
|
|
87
|
+
default: 默认值
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
配置值
|
|
91
|
+
"""
|
|
92
|
+
if key is None:
|
|
93
|
+
return ConfigLoader.load("scoring.yaml")
|
|
94
|
+
return ConfigLoader.get("scoring.yaml", key, default)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def get_limit_config(key: str = None, default: Any = None) -> Any:
|
|
98
|
+
"""
|
|
99
|
+
获取涨跌停限制配置。
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
key: 键路径,为空时返回整个配置
|
|
103
|
+
default: 默认值
|
|
104
|
+
"""
|
|
105
|
+
if key is None:
|
|
106
|
+
return ConfigLoader.load("limits.yaml")
|
|
107
|
+
return ConfigLoader.get("limits.yaml", key, default)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def get_industry_threshold(industry: str, metric: str, default: float) -> float:
|
|
111
|
+
"""
|
|
112
|
+
获取行业差异化阈值。
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
industry: 行业名称
|
|
116
|
+
metric: 指标名称 (如 "pe_undervalued")
|
|
117
|
+
default: 默认值
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
阈值
|
|
121
|
+
"""
|
|
122
|
+
# 先尝试从行业阈���配置获取
|
|
123
|
+
value = ConfigLoader.get(
|
|
124
|
+
"industry_thresholds.yaml",
|
|
125
|
+
f"thresholds.{industry}.{metric}",
|
|
126
|
+
None
|
|
127
|
+
)
|
|
128
|
+
if value is not None:
|
|
129
|
+
return float(value)
|
|
130
|
+
|
|
131
|
+
# 回退到默认行业配置
|
|
132
|
+
return ConfigLoader.get(
|
|
133
|
+
"scoring.yaml",
|
|
134
|
+
f"industry_defaults.{metric}",
|
|
135
|
+
default
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def reload_config(filename: str = None):
|
|
140
|
+
"""重新加载配置。"""
|
|
141
|
+
ConfigLoader.reload(filename)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# 盘中消息推送配置
|
|
2
|
+
# 文档: https://github.com/user/stock-analyzer-skill/wiki/notifications
|
|
3
|
+
|
|
4
|
+
# 推送通道配置
|
|
5
|
+
channels:
|
|
6
|
+
bark:
|
|
7
|
+
enabled: false
|
|
8
|
+
server: "https://api.day.app" # Bark 服务器地址(支持自托管)
|
|
9
|
+
key: "" # Bark 推送 Key
|
|
10
|
+
group: "stock" # iOS 通知分组名
|
|
11
|
+
|
|
12
|
+
# wechat_work:
|
|
13
|
+
# enabled: false
|
|
14
|
+
# webhook: "" # 企业微信机器人 Webhook URL
|
|
15
|
+
|
|
16
|
+
# dingtalk:
|
|
17
|
+
# enabled: false
|
|
18
|
+
# webhook: "" # 钉钉机器人 Webhook URL
|
|
19
|
+
|
|
20
|
+
# webhook:
|
|
21
|
+
# enabled: false
|
|
22
|
+
# url: "" # 自定义 Webhook URL
|
|
23
|
+
|
|
24
|
+
# 预警规则
|
|
25
|
+
rules:
|
|
26
|
+
price_alert:
|
|
27
|
+
enabled: true
|
|
28
|
+
thresholds:
|
|
29
|
+
default: 3.0 # 默认涨跌幅阈值 (%)
|
|
30
|
+
overrides: {} # 个股自定义: {"sh600989": 5.0}
|
|
31
|
+
support_resistance: true # 触及支撑/压力位推送
|
|
32
|
+
near_limit: true # 涨跌停附近推送
|
|
33
|
+
|
|
34
|
+
technical_alert:
|
|
35
|
+
enabled: true
|
|
36
|
+
macd_cross: true # MACD 金叉/死叉
|
|
37
|
+
ma_break: [20, 60] # 均线突破
|
|
38
|
+
volume_surge: 2.0 # 量比阈值
|
|
39
|
+
chan_signal: true # 缠论买卖点
|
|
40
|
+
|
|
41
|
+
portfolio_alert:
|
|
42
|
+
enabled: true
|
|
43
|
+
risk_change: true # 风险状态变更
|
|
44
|
+
underperform_days: 2 # 连续跑输天数
|
|
45
|
+
concentration: true # 集中度超标
|
|
46
|
+
|
|
47
|
+
market_alert:
|
|
48
|
+
enabled: true
|
|
49
|
+
index_change: 2.0 # 大盘涨跌幅阈值 (%)
|
|
50
|
+
sector_moved: true # 持仓板块异动
|
|
51
|
+
northbound_flow: 50 # 北向资金净流入/出 (亿)
|
|
52
|
+
|
|
53
|
+
# 频率控制
|
|
54
|
+
throttle:
|
|
55
|
+
dedup_window: 15 # 同类消息去重窗口 (分钟)
|
|
56
|
+
daily_limit: 20 # 每日推送上限
|
|
57
|
+
quiet_hours: "15:05-09:25" # 非交易时段静默
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# A 股评分系统配置
|
|
2
|
+
|
|
3
|
+
# 均线排列评分
|
|
4
|
+
alignment_scores:
|
|
5
|
+
多头排列: 20
|
|
6
|
+
交叉震荡: 12
|
|
7
|
+
空头排列: 3
|
|
8
|
+
数据不足: 7
|
|
9
|
+
|
|
10
|
+
# MACD 评分
|
|
11
|
+
macd_scores:
|
|
12
|
+
金叉放大: 15
|
|
13
|
+
金叉: 10
|
|
14
|
+
死叉: 3
|
|
15
|
+
中性: 7
|
|
16
|
+
|
|
17
|
+
# 市场环境权重调整
|
|
18
|
+
market_weights:
|
|
19
|
+
牛市:
|
|
20
|
+
bullish_bias: 1.3
|
|
21
|
+
trend_following: 1.4
|
|
22
|
+
breakout: 1.3
|
|
23
|
+
divergence_bottom: 0.5
|
|
24
|
+
buy_point_1: 0.5
|
|
25
|
+
buy_point_3: 1.3
|
|
26
|
+
overbought: 0.8
|
|
27
|
+
desc: "牛市:趋势跟随加权,底背离/一买降权"
|
|
28
|
+
|
|
29
|
+
熊市:
|
|
30
|
+
bullish_bias: 1.5
|
|
31
|
+
trend_following: 0.6
|
|
32
|
+
breakout: 0.6
|
|
33
|
+
divergence_bottom: 1.5
|
|
34
|
+
buy_point_1: 1.5
|
|
35
|
+
buy_point_3: 0.5
|
|
36
|
+
overbought: 1.3
|
|
37
|
+
desc: "熊市:反转信号加权,追涨信号降权"
|
|
38
|
+
|
|
39
|
+
震荡:
|
|
40
|
+
bullish_bias: 1.0
|
|
41
|
+
trend_following: 0.8
|
|
42
|
+
breakout: 0.8
|
|
43
|
+
divergence_bottom: 1.2
|
|
44
|
+
buy_point_1: 1.1
|
|
45
|
+
buy_point_3: 1.2
|
|
46
|
+
overbought: 1.0
|
|
47
|
+
desc: "震荡:反转+区间交易加权,趋势信号降权"
|
|
48
|
+
|
|
49
|
+
冰点:
|
|
50
|
+
bullish_bias: 1.8
|
|
51
|
+
trend_following: 0.3
|
|
52
|
+
breakout: 0.4
|
|
53
|
+
divergence_bottom: 1.8
|
|
54
|
+
buy_point_1: 2.0
|
|
55
|
+
buy_point_3: 0.3
|
|
56
|
+
overbought: 1.5
|
|
57
|
+
desc: "冰点:极度超卖反转加权,趋势信号大幅降权"
|
|
58
|
+
|
|
59
|
+
亢奋:
|
|
60
|
+
bullish_bias: 0.6
|
|
61
|
+
trend_following: 0.5
|
|
62
|
+
breakout: 0.5
|
|
63
|
+
divergence_bottom: 0.4
|
|
64
|
+
buy_point_1: 0.3
|
|
65
|
+
buy_point_3: 0.5
|
|
66
|
+
overbought: 0.3
|
|
67
|
+
desc: "亢奋:全面保守,警惕反转"
|
|
68
|
+
|
|
69
|
+
# 个股类型 × 指标权重
|
|
70
|
+
stock_type_weights:
|
|
71
|
+
题材股:
|
|
72
|
+
ma: 0.6
|
|
73
|
+
macd: 0.5
|
|
74
|
+
kdj: 0.5
|
|
75
|
+
boll: 0.8
|
|
76
|
+
rsi: 1.0
|
|
77
|
+
volume: 1.3
|
|
78
|
+
pattern: 1.5
|
|
79
|
+
limit: 1.5
|
|
80
|
+
chan: 0.5
|
|
81
|
+
|
|
82
|
+
蓝筹股:
|
|
83
|
+
ma: 1.3
|
|
84
|
+
macd: 1.1
|
|
85
|
+
kdj: 0.4
|
|
86
|
+
boll: 1.2
|
|
87
|
+
rsi: 0.9
|
|
88
|
+
volume: 0.8
|
|
89
|
+
pattern: 0.7
|
|
90
|
+
limit: 0.3
|
|
91
|
+
chan: 0.8
|
|
92
|
+
|
|
93
|
+
强成长股:
|
|
94
|
+
ma: 0.9
|
|
95
|
+
macd: 1.3
|
|
96
|
+
kdj: 0.4
|
|
97
|
+
boll: 1.2
|
|
98
|
+
rsi: 0.9
|
|
99
|
+
volume: 1.2
|
|
100
|
+
pattern: 0.8
|
|
101
|
+
limit: 0.5
|
|
102
|
+
chan: 0.7
|
|
103
|
+
|
|
104
|
+
周期股:
|
|
105
|
+
ma: 0.6
|
|
106
|
+
macd: 1.3
|
|
107
|
+
kdj: 1.2
|
|
108
|
+
boll: 1.0
|
|
109
|
+
rsi: 0.9
|
|
110
|
+
volume: 0.9
|
|
111
|
+
pattern: 0.7
|
|
112
|
+
limit: 0.4
|
|
113
|
+
chan: 1.3
|
|
114
|
+
|
|
115
|
+
稳成长股:
|
|
116
|
+
ma: 1.2
|
|
117
|
+
macd: 1.1
|
|
118
|
+
kdj: 0.5
|
|
119
|
+
boll: 1.0
|
|
120
|
+
rsi: 1.0
|
|
121
|
+
volume: 0.9
|
|
122
|
+
pattern: 1.0
|
|
123
|
+
limit: 0.3
|
|
124
|
+
chan: 0.8
|
|
125
|
+
|
|
126
|
+
防御股:
|
|
127
|
+
ma: 0.8
|
|
128
|
+
macd: 0.9
|
|
129
|
+
kdj: 0.6
|
|
130
|
+
boll: 1.1
|
|
131
|
+
rsi: 1.1
|
|
132
|
+
volume: 0.7
|
|
133
|
+
pattern: 0.7
|
|
134
|
+
limit: 0.3
|
|
135
|
+
chan: 0.9
|
|
136
|
+
|
|
137
|
+
普通股:
|
|
138
|
+
ma: 1.0
|
|
139
|
+
macd: 1.0
|
|
140
|
+
kdj: 1.0
|
|
141
|
+
boll: 1.0
|
|
142
|
+
rsi: 1.0
|
|
143
|
+
volume: 1.0
|
|
144
|
+
pattern: 1.0
|
|
145
|
+
limit: 1.0
|
|
146
|
+
chan: 1.0
|
|
147
|
+
|
|
148
|
+
# 默认行业阈值
|
|
149
|
+
industry_defaults:
|
|
150
|
+
pe_undervalued: 15
|
|
151
|
+
pe_reasonable: 25
|
|
152
|
+
pe_expensive: 40
|
|
153
|
+
peg_undervalued: 0.8
|
|
154
|
+
peg_reasonable: 1.5
|
|
155
|
+
roe_excellent: 20
|
|
156
|
+
gross_margin_min: 20
|
|
157
|
+
debt_ratio_max: 60
|
|
158
|
+
profit_growth_excellent: 40
|
|
159
|
+
revenue_growth_excellent: 30
|
|
Binary file
|
|
Binary file
|
package/scripts/data/config.py
CHANGED
|
@@ -1,13 +1,27 @@
|
|
|
1
|
-
"""统一配置管理。
|
|
1
|
+
"""统一配置管理。
|
|
2
|
+
|
|
3
|
+
配置优先级:环境变量 > YAML 配置 > 代码默认值
|
|
4
|
+
"""
|
|
2
5
|
import os
|
|
6
|
+
import time
|
|
3
7
|
from dataclasses import dataclass
|
|
4
8
|
|
|
5
9
|
|
|
10
|
+
def _load_yaml_config() -> dict:
|
|
11
|
+
"""从 ConfigLoader 加载 YAML 配置(延迟导入避免循环依赖)。"""
|
|
12
|
+
try:
|
|
13
|
+
from config.loader import ConfigLoader
|
|
14
|
+
return ConfigLoader.load("data_source.yaml")
|
|
15
|
+
except Exception:
|
|
16
|
+
return {}
|
|
17
|
+
|
|
18
|
+
|
|
6
19
|
@dataclass
|
|
7
20
|
class DataConfig:
|
|
8
21
|
"""数据层配置。"""
|
|
9
22
|
# 缓存 TTL (秒)
|
|
10
|
-
quote_cache_ttl: int = 900 # 15
|
|
23
|
+
quote_cache_ttl: int = 900 # 15 分钟(盘后)
|
|
24
|
+
intraday_quote_cache_ttl: int = 90 # 90 秒(盘中)
|
|
11
25
|
kline_cache_ttl: int = 21600 # 6 小时
|
|
12
26
|
finance_cache_ttl: int = 21600 # 6 小时
|
|
13
27
|
ann_cache_ttl: int = 1800 # 30 分钟
|
|
@@ -20,10 +34,24 @@ class DataConfig:
|
|
|
20
34
|
max_workers: int = 8
|
|
21
35
|
|
|
22
36
|
@classmethod
|
|
23
|
-
def
|
|
24
|
-
"""
|
|
37
|
+
def from_yaml_and_env(cls) -> "DataConfig":
|
|
38
|
+
"""从 YAML 配置加载默认值,环境变量覆盖。"""
|
|
39
|
+
yaml_cfg = _load_yaml_config()
|
|
40
|
+
cache_cfg = yaml_cfg.get("cache", {})
|
|
41
|
+
cb_cfg = yaml_cfg.get("circuit_breaker", {})
|
|
42
|
+
|
|
25
43
|
cfg = cls()
|
|
44
|
+
# YAML 默认值
|
|
45
|
+
cfg.quote_cache_ttl = cache_cfg.get("quote_ttl", cfg.quote_cache_ttl)
|
|
46
|
+
cfg.kline_cache_ttl = cache_cfg.get("kline_ttl", cfg.kline_cache_ttl)
|
|
47
|
+
cfg.finance_cache_ttl = cache_cfg.get("finance_ttl", cfg.finance_cache_ttl)
|
|
48
|
+
cfg.ann_cache_ttl = cache_cfg.get("ann_ttl", cfg.ann_cache_ttl)
|
|
49
|
+
cfg.circuit_failure_threshold = cb_cfg.get("failure_threshold", cfg.circuit_failure_threshold)
|
|
50
|
+
cfg.circuit_recovery_timeout = cb_cfg.get("recovery_timeout", cfg.circuit_recovery_timeout)
|
|
51
|
+
|
|
52
|
+
# 环境变量覆盖
|
|
26
53
|
cfg.quote_cache_ttl = int(os.getenv("DATA_QUOTE_TTL", cfg.quote_cache_ttl))
|
|
54
|
+
cfg.intraday_quote_cache_ttl = int(os.getenv("DATA_INTRADAY_QUOTE_TTL", cfg.intraday_quote_cache_ttl))
|
|
27
55
|
cfg.kline_cache_ttl = int(os.getenv("DATA_KLINE_TTL", cfg.kline_cache_ttl))
|
|
28
56
|
cfg.finance_cache_ttl = int(os.getenv("DATA_FINANCE_TTL", cfg.finance_cache_ttl))
|
|
29
57
|
cfg.circuit_failure_threshold = int(os.getenv("DATA_CIRCUIT_THRESHOLD", cfg.circuit_failure_threshold))
|
|
@@ -31,6 +59,30 @@ class DataConfig:
|
|
|
31
59
|
cfg.max_workers = int(os.getenv("DATA_MAX_WORKERS", cfg.max_workers))
|
|
32
60
|
return cfg
|
|
33
61
|
|
|
62
|
+
@classmethod
|
|
63
|
+
def from_env(cls) -> "DataConfig":
|
|
64
|
+
"""向后兼容:从环境变量加载配置。"""
|
|
65
|
+
return cls.from_yaml_and_env()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def is_trading_hours() -> bool:
|
|
69
|
+
"""判断当前是否在 A 股交易时段(9:15-15:00,周一至周五)。"""
|
|
70
|
+
now = time.localtime()
|
|
71
|
+
# 周末不交易
|
|
72
|
+
if now.tm_wday >= 5:
|
|
73
|
+
return False
|
|
74
|
+
# 交易时段:9:15 - 15:00
|
|
75
|
+
current_minutes = now.tm_hour * 60 + now.tm_min
|
|
76
|
+
return 9 * 60 + 15 <= current_minutes <= 15 * 60
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def get_quote_cache_ttl() -> int:
|
|
80
|
+
"""获取行情缓存 TTL(盘中短,盘后长)。"""
|
|
81
|
+
cfg = get_config()
|
|
82
|
+
if is_trading_hours():
|
|
83
|
+
return cfg.intraday_quote_cache_ttl
|
|
84
|
+
return cfg.quote_cache_ttl
|
|
85
|
+
|
|
34
86
|
|
|
35
87
|
_config = None
|
|
36
88
|
|