股票评价系统
一、目的意义
本文介绍了一个基于Tkinter的股票数据处理应用程序,它提供了抓取、清洗和评估股票数据的功能。该应用程序通过网络抓取股票数据,并将数据保存到CSV文件中。然后,它执行数据清洗操作,包括移除空数据行、替换市盈率为负的值为最大市盈率,并过滤特定股票代码和名称的股票。最后,用户可以输入权重值,对清洗后的数据进行评估,计算每只股票的评价分数。评价分数基于股票的最新价、涨跌幅、成交量、市盈率和振幅等指标计算得出。应用程序将排名靠前的股票代码和评分结果显示给用户,并通过弹窗展示结果。
二、主要功能
1. 抓取数据
通过点击"抓取数据"按钮,应用程序会从指定的网址抓取股票数据,并将数据保存到名为"stock_data.csv"的CSV文件中。
def clean_stock_data():
with open('stock_data.csv', 'r', newline='', encoding='utf-8') as file:
reader = csv.DictReader(file)
pe_ratios = [float(row['市盈率']) for row in reader if row['市盈率'] != '-' and row['市盈率'] != '']
max_pe_ratio = 150
# 重新打开CSV文件以重置读取器
file.seek(0)
next(reader) # 跳过标题行
cleaned_rows = [row for row in reader if clean_data(row, max_pe_ratio) and all(value != '' and value != '-' for value in row.values())]
2. 清洗数据
点击"清洗数据"按钮,应用程序会读取"stock_data.csv"文件中的数据,并进行数据清洗。清洗的过程包括移除包含空数据的行,替换市盈率为负的值为市盈率的最大值,以及移除股票代码以600、00或8开头的股票和股票名称中包含"ST"的股票。清洗后的数据将被保存到名为"cleaned_stock_data.csv"的新CSV文件中。
# 将清洗后的数据写入新的CSV文件
cleaned_filename = 'cleaned_stock_data.csv'
with open(cleaned_filename, 'w', newline='', encoding='utf-8') as file:
writer = csv.DictWriter(file, fieldnames=reader.fieldnames)
writer.writeheader()
writer.writerows(cleaned_rows)
3. 评估股票
用户可以在界面上输入权重值,然后点击"评估股票"按钮进行股票评估。应用程序会读取"cleaned_stock_data.csv"文件中的数据,并根据用户输入的权重计算每只股票的评价分数。评价分数是根据股票的最新价、涨跌幅、成交量、市盈率和振幅等指标计算得出的。计算完成后,应用程序会将评分排名靠前的股票代码和评分结果显示在界面上,并通过messagebox.showinfo弹窗显示结果。
def evaluate_stocks():
# 用户自定义的权重
user_weights = {
'最新价': float(weights_entry['最新价'].get()),
'涨跌幅': float(weights_entry['涨跌幅'].get()),
'成交量': float(weights_entry['成交量'].get()),
'市盈率': float(weights_entry['市盈率'].get()),
'振幅': float(weights_entry['振幅'].get())
}
# 存储股票评价指数的字典
stock_scores = {}
# 读取CSV文件
with open('cleaned_stock_data.csv', 'r', newline='', encoding='utf-8') as file:
reader = csv.DictReader(file)
for row in reader:
# 计算每只股票的评价分数
stock_score = calculate_score(row, user_weights)
# 将评价指数存储到字典中
stock_scores[row['股票代码']] = stock_score
# 按评价指数从高到低排序股票
sorted_stocks = sorted(stock_scores.items(), key=lambda x: x[1], reverse=True)
# 输出排序后的股票列表
for stock_code, score in sorted_stocks:
print(f"股票代码: {stock_code}, 评分: {score}")
result_text = ""
for stock_code, score in sorted_stocks[:20]:
result_text += f"股票代码: {stock_code}, 评分: {score}\n"
# 使用messagebox.showinfo显示结果
messagebox.showinfo("排名靠前的股票信息", result_text)
4. 用户界面
应用程序使用Tkinter库创建了一个简单的GUI界面,包含几个输入框和按钮,用于输入股票代码、开始日期和结束日期,以及触发相应的操作。
window = tk.Tk()
window.title("股票数据处理")
window.geometry("600x300")
# 创建控件
fetch_data_button = tk.Button(window, text="抓取数据", command=fetch_stock_all_data)
fetch_data_button.pack(pady=10)
clean_data_button = tk.Button(window, text="清洗数据", command=clean_stock_data)
clean_data_button.pack(pady=10)
weights_label = tk.Label(window, text="请输入权重:")
weights_label.pack(pady=10)
weights_entry = {}
weight_labels = ['最新价', '涨跌幅', '成交量', '市盈率', '振幅']
for label in weight_labels:
frame = tk.Frame(window)
frame.pack()
label_widget = tk.Label(frame, text=label)
label_widget.pack(side=tk.LEFT)
entry_widget = tk.Entry(frame)
entry_widget.pack(side=tk.LEFT)
weights_entry[label] = entry_widget
evaluate_stocks_button = tk.Button(window, text="评估股票", command=evaluate_stocks)
evaluate_stocks_button.pack(pady=10)
# 运行主窗口的消息循环
window.mainloop()
三、完整代码
import requests
import json
import os
import csv
from sklearn.preprocessing import StandardScaler
import tkinter as tk
from tkinter import messagebox
def fetch_stock_all_data():
json_url = "http://48.push2.eastmoney.com/api/qt/clist/get?cb=jQuery112402508937289440778_1658838703304&pn={page}&pz=20&po=1&np=1&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&invt=2&wbp2u=|0|0|0|web&fid=f3&fs=m:0+t:6,m:0+t:80,m:1+t:2,m:1+t:23,m:0+t:81+s:2048&fields=f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f12,f13,f14,f15,f16,f17,f18,f20,f21,f23,f24,f25,f22,f11,f62,f128,f136,f115,f152&_=1658838703305"
filename = "stock_data.csv"
if not os.path.exists(filename):
with open(filename, "w", encoding="utf-8") as f:
f.write("股票代码,股票名称,最新价,涨跌幅,涨跌额,成交量(手),成交额,振幅,换手率,市盈率,量比,最高,最低,今开,昨收,市净率\n")
for i in range(1, 300):
print("抓取网页%s" % str(i))
res = requests.get(json_url.format(page=str(i)))
result = res.text.split("jQuery112402508937289440778_1658838703304")[1].split("(")[1].split(");")[0]
result_json = json.loads(result)
try:
stock_data = result_json['data']['diff']
except:
print('over')
break
with open(filename, "a", encoding="utf-8") as f:
for j in stock_data:
Code = j["f12"]
Name = j["f14"]
Close = j['f2']
ChangePercent = j["f3"]
Change = j['f4']
Volume = j['f5']
Amount = j['f6']
Amplitude = j['f7']
TurnoverRate = j['f8']
PERation = j['f9']
VolumeRate = j['f10']
Hign = j['f15']
Low = j['f16']
Open = j['f17']
PreviousClose = j['f18']
PB = j['f22']
row = '{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}\n'.format(
Code, Name, Close, ChangePercent, Change, Volume, Amount, Amplitude,
TurnoverRate, PERation, VolumeRate, Hign, Low, Open, PreviousClose, PB)
f.write(row)
def clean_data(row, max_pe_ratio):
# 检查数据行中是否存在空数据
for value in row.values():
if value == '' or value == '-':
return False
# 将市盈率为负的值替换为市盈率的最大值
pe_ratio = float(row['市盈率'])
if pe_ratio < 0:
row['市盈率'] = str(max_pe_ratio)
# 检查股票代码是否以600、00或8开头,如果是则返回False
stock_code = row['股票代码']
if stock_code.startswith(('600', '00', '8')):
return False
# 检查股票名称是否包含'ST',如果是则返回False
stock_name = row['股票名称']
if 'ST' in stock_name:
return False
return True
def clean_stock_data():
# 读取CSV文件
with open('stock_data.csv', 'r', newline='', encoding='utf-8') as file:
reader = csv.DictReader(file)
pe_ratios = [float(row['市盈率']) for row in reader if row['市盈率'] != '-' and row['市盈率'] != '']
max_pe_ratio = 150
# 重新打开CSV文件以重置读取器
file.seek(0)
next(reader) # 跳过标题行
cleaned_rows = [row for row in reader if clean_data(row, max_pe_ratio) and all(value != '' and value != '-' for value in row.values())]
# 将清洗后的数据写入新的CSV文件
cleaned_filename = 'cleaned_stock_data.csv'
with open(cleaned_filename, 'w', newline='', encoding='utf-8') as file:
writer = csv.DictWriter(file, fieldnames=reader.fieldnames)
writer.writeheader()
writer.writerows(cleaned_rows)
def calculate_score(data, weights):
# 从数据中提取所需的字段
latest_price = float(data['最新价'])
change_percent = float(data['涨跌幅'].replace('%', ''))
volume = int(data['成交量(手)'].replace(',', ''))
pe_ratio = float(data['市盈率'])
shock = float(data['振幅'].replace('%', ''))
# 标准化处理
scaler = StandardScaler()
scaler.fit([[latest_price], [change_percent], [volume], [1 / pe_ratio], [shock]]) # 使用 pe_ratio
scaled_price = scaler.transform([[latest_price]])[0][0]
scaled_change = scaler.transform([[change_percent]])[0][0]
scaled_volume = scaler.transform([[volume]])[0][0]
scaled_pe_ratio = scaler.transform([[1 / pe_ratio]])[0][0]
scaled_shock = scaler.transform([[shock]])[0][0]
# 根据权重计算评价分数
score = (scaled_price * weights['最新价'] +
scaled_change * weights['涨跌幅'] +
scaled_volume * weights['成交量'] +
scaled_pe_ratio * weights['市盈率'] +
scaled_shock * weights['振幅'])
return score
def evaluate_stocks():
# 用户自定义的权重
user_weights = {
'最新价': float(weights_entry['最新价'].get()),
'涨跌幅': float(weights_entry['涨跌幅'].get()),
'成交量': float(weights_entry['成交量'].get()),
'市盈率': float(weights_entry['市盈率'].get()),
'振幅': float(weights_entry['振幅'].get())
}
# 存储股票评价指数的字典
stock_scores = {}
# 读取CSV文件
with open('cleaned_stock_data.csv', 'r', newline='', encoding='utf-8') as file:
reader = csv.DictReader(file)
for row in reader:
# 计算每只股票的评价分数
stock_score = calculate_score(row, user_weights)
# 将评价指数存储到字典中
stock_scores[row['股票代码']] = stock_score
# 按评价指数从高到低排序股票
sorted_stocks = sorted(stock_scores.items(), key=lambda x: x[1], reverse=True)
# 输出排序后的股票列表
for stock_code, score in sorted_stocks:
print(f"股票代码: {stock_code}, 评分: {score}")
result_text = ""
for stock_code, score in sorted_stocks[:20]:
result_text += f"股票代码: {stock_code}, 评分: {score}\n"
# 使用messagebox.showinfo显示结果
messagebox.showinfo("排名靠前的股票信息", result_text)
window = tk.Tk()
window.title("股票数据处理")
window.geometry("600x300")
# 创建控件
fetch_data_button = tk.Button(window, text="抓取数据", command=fetch_stock_all_data)
fetch_data_button.pack(pady=10)
clean_data_button = tk.Button(window, text="清洗数据", command=clean_stock_data)
clean_data_button.pack(pady=10)
weights_label = tk.Label(window, text="请输入权重:")
weights_label.pack(pady=10)
weights_entry = {}
weight_labels = ['最新价', '涨跌幅', '成交量', '市盈率', '振幅']
for label in weight_labels:
frame = tk.Frame(window)
frame.pack()
label_widget = tk.Label(frame, text=label)
label_widget.pack(side=tk.LEFT)
entry_widget = tk.Entry(frame)
entry_widget.pack(side=tk.LEFT)
weights_entry[label] = entry_widget
evaluate_stocks_button = tk.Button(window, text="评估股票", command=evaluate_stocks)
evaluate_stocks_button.pack(pady=10)
# 运行主窗口的消息循环
window.mainloop()
这个应用程序的目的是帮助用户方便地抓取、清洗和评估股票数据。通过使用这个应用程序,用户可以获取最新的股票数据,并通过自定义权重对股票进行评估,以辅助他们做出更明智的投资决策。
如有共同爱好或者交流,可以加Q:2388627579!