-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstock_selector.py
More file actions
241 lines (195 loc) · 7.16 KB
/
Copy pathstock_selector.py
File metadata and controls
241 lines (195 loc) · 7.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
股票选股工具 - 小白版
一键选股,直接出结果,无需配置
"""
import requests
import pandas as pd
from datetime import datetime
import os
class StockSelector:
"""股票选股器"""
def __init__(self):
self.selected_stocks = []
def get_realtime_data(self):
"""获取 A 股实时行情数据"""
print("正在获取股票数据...", end="", flush=True)
try:
url = "http://push2.eastmoney.com/api/qt/clist/get"
params = {
"pn": "1",
"pz": "500",
"po": "1",
"np": "1",
"ut": "bd1d9ddb04089700cf9c27f6f74262da",
"fltt": "2",
"invt": "2",
"fid": "f3",
"fs": "m:0 t:6,m:0 t:80,m:1 t:2,m:1 t:23",
"fields": "f12,f14,f2,f3,f4,f5,f6,f8,f9,f10,f15,f16,f17,f18,f20,f21,f22,f25,f37,f38,f39,f41"
}
response = requests.get(url, params=params, timeout=10)
data = response.json()
if data['data'] and data['data']['diff']:
stocks = data['data']['diff']
df = pd.DataFrame(stocks)
df.rename(columns={
'f12': '代码', 'f14': '名称', 'f2': '最新价', 'f3': '涨跌幅',
'f4': '涨跌额', 'f5': '成交量', 'f6': '成交额', 'f8': '换手率',
'f9': '量比', 'f10': '流通市值', 'f20': '总市值', 'f21': '市盈率',
'f22': '市净率', 'f25': '振幅', 'f37': '5 日均线', 'f38': '10 日均线',
'f39': '20 日均线', 'f41': '60 日均线',
}, inplace=True)
print(f" 获取到 {len(df)} 只股票")
return df
else:
print(" 获取失败")
return None
except Exception as e:
print(f" 获取失败:{e}")
return None
def screen_stocks(self, df, strategy):
"""按策略选股"""
if df is None:
return []
selected = []
for idx, row in df.iterrows():
try:
code = row['代码']
name = row['名称']
price = row['最新价']
change = row['涨跌幅']
volume_ratio = row.get('量比', 0)
turnover = row.get('换手率', 0)
market_cap = row.get('总市值', 0) / 100000000
pe = row.get('市盈率', 0)
ma5 = row.get('5 日均线', 0)
# 跳过 ST、停牌、价格无效
if 'ST' in str(name) or 'st' in str(name):
continue
if price == 0 or pd.isna(price):
continue
match = False
reasons = []
if strategy == '强势股':
# 涨幅 2%-7%,量比>1.2,股价在 5 日线上
if 2 <= change <= 7 and volume_ratio > 1.2 and price > ma5 and ma5 > 0:
match = True
reasons = [f"涨 {change:+.1f}%", f"量比{volume_ratio:.1f}", "站上 5 日线"]
elif strategy == '潜力股':
# 涨幅 -1%-5%,换手 3%-20%,市值 30-500 亿
if -1 <= change <= 5 and 3 <= turnover <= 20 and 30 <= market_cap <= 500:
match = True
reasons = [f"涨 {change:+.1f}%", f"换手{turnover:.1f}%", f"市值{market_cap:.0f}亿"]
elif strategy == '稳健股':
# 上涨,市盈率 0-50,股价 3-200 元
if change > 0 and 0 < pe < 50 and 3 <= price <= 200:
match = True
reasons = [f"涨 {change:+.1f}%", f"PE{pe:.1f}", f"股价{price:.1f}元"]
if match:
selected.append({
'代码': code,
'名称': name,
'价格': round(price, 2),
'涨幅': round(change, 2),
'理由': ' | '.join(reasons)
})
except Exception:
continue
return selected
def print_results(self, stocks, title="选股结果"):
"""打印结果"""
if not stocks:
print(" 没有符合条件的股票")
return
print(f"\n{'='*60}")
print(f" {title} - 共 {len(stocks)} 只")
print(f"{'='*60}")
print(f" {'代码':<10} {'名称':<10} {'价格':>8} {'涨幅':>10} 选股理由")
print(f" {'-'*50}")
for s in stocks[:15]:
print(f" {s['代码']:<10} {s['名称']:<10} {s['价格']:>8.2f} {s['涨幅']:>10.2f}% {s['理由']}")
if len(stocks) > 15:
print(f" ... 还有 {len(stocks) - 15} 只,请查看 CSV 文件")
print(f"{'='*60}")
def save_results(self, stocks, filename):
"""保存 CSV"""
if not stocks:
return
df = pd.DataFrame(stocks)
df.to_csv(filename, index=False, encoding='utf-8-sig')
print(f" 已保存:{filename}")
def run_screen():
"""执行选股"""
selector = StockSelector()
df = selector.get_realtime_data()
if df is None:
print("数据获取失败,请检查网络连接后重试")
return
# 三个策略都跑一遍
strategies = [
('强势股', '选股结果_强势股.csv'),
('潜力股', '选股结果_潜力股.csv'),
('稳健股', '选股结果_稳健股.csv'),
]
all_results = {}
for name, file in strategies:
print(f"\n正在筛选【{name}】...")
result = selector.screen_stocks(df, name)
selector.print_results(result, name)
selector.save_results(result, file)
all_results[name] = result
print(f"\n{'='*60}")
print("选股完成!")
print(f"{'='*60}")
for name, result in all_results.items():
print(f" {name}: {len(result)} 只")
print(f"\nCSV 文件已保存到当前目录")
def show_help():
"""显示帮助"""
print(f"""
{'='*60}
股票选股工具 - 使用说明
{'='*60}
本工具提供三种选股策略:
【强势股】适合追涨
- 涨幅 3%-6%
- 量比大于 1.5
- 股价在 5 日均线上方
【潜力股】适合潜伏
- 涨幅 0%-3%
- 换手率 5%-15%
- 市值 50-300 亿
【稳健股】适合保守
- 当日上涨
- 市盈率 0-30
- 股价 5-100 元
选股结果会自动保存为 CSV 文件
{'='*60}
""")
def main():
"""主菜单"""
while True:
print(f"""
{'='*50}
股票选股工具 v2.0
{'='*50}
1. 一键选股(推荐)
2. 使用说明
0. 退出
{'='*50}
""")
choice = input(" 请选择:").strip()
if choice == '1':
run_screen()
elif choice == '2':
show_help()
elif choice == '0':
print(" 再见!")
break
else:
print(" 无效选择,请重新输入")
input("\n 按回车键继续...")
if __name__ == "__main__":
main()