基于Tkinter的股票预测应用程序:使用SMA和线性回归模型预测股票价格
一、目的意义
这个基于Tkinter的股票预测应用程序的目的是帮助股票投资者或交易者进行更准确的预测和决策。通过分析历史的股票价格数据,应用程序使用SMA指标和线性回归模型来预测股票的下一日开盘价和收盘价。
- 这个基于Tkinter的股票预测应用程序的目的是帮助股票投资者或交易者进行更准确的预测和决策。通过分析历史的股票价格数据,应用程序使用SMA指标和线性回归模型来预测股票的下一日开盘价和收盘价。
- 减少主观偏差:通过使用计算机算法和机器学习模型进行预测,应用程序可以减少主观偏差的影响。它基于历史数据和统计模型进行分析,提供了一个客观的参考,使投资者能够更加理性地评估股票的走势和潜在风险。
- 提供决策支持:预测的结果和评估指标可以为投资者提供决策支持。通过了解预测的下一日开盘价和收盘价,投资者可以更好地制定买入、卖出或持有股票的策略,从而优化他们的投资组合和获得更好的投资回报。
二、主要功能
1. 用户界面
应用程序使用Tkinter库创建了一个简单的GUI界面,包含几个输入框和按钮,用于输入股票代码、开始日期和结束日期,以及触发相应的操作。
# 创建主窗口
root = Tk()
root.title('股票预测')
root.geometry('400x300')
# 股票代码标签和输入框
code_label = Label(root, text='股票代码:')
code_label.pack()
code_entry = Entry(root)
code_entry.pack()
# 开始日期标签和输入框
start_date_label = Label(root, text='开始日期:')
start_date_label.pack()
start_date_entry = Entry(root)
start_date_entry.pack()
# 结束日期标签和输入框
end_date_label = Label(root, text='结束日期:')
end_date_label.pack()
end_date_entry = Entry(root)
end_date_entry.pack()
# 获取数据按钮
fetch_data_button = Button(root, text='获取数据', command=fetch_stock_data)
fetch_data_button.pack()
# 预测按钮
predict_button = Button(root, text='预测', command=predict_next_day_price)
predict_button.pack()
# 运行主窗口的消息循环
root.mainloop()
2. 获取股票历史数据
通过调用get_k_history()
函数,应用程序从指定的股票数据源获取股票的K线历史数据。函数会根据输入的股票代码、开始日期和结束日期构建请求,并解析返回的数据,生成一个包含日期、开盘价、收盘价等信息的数据框。
json_response: dict = requests.get(url, headers=EastmoneyHeaders).json()
data = json_response.get('data')
if data is None:
if secid[0] == '0':
secid = f'1.{code}'
else:
secid = f'0.{code}'
params['secid'] = secid
url = base_url + '?' + urlencode(params)
json_response: dict = requests.get(url, headers=EastmoneyHeaders).json()
data = json_response.get('data')
if data is None:
messagebox.showerror('错误', f'股票代码: {code} 可能有误')
return pd.DataFrame(columns=columns)
klines = data['klines']
3. 特征工程
在获取的股票历史数据基础上进行特征工程。这里采用了简单的方法,即添加前一日至前三日的开盘价和收盘价作为目标变量。这样,我们将每个样本的特征数据定义为成交额、换手率、振幅以及前一日至前三日的开盘价和收盘价。`
# 添加前一日至前三日的开盘价和收盘价作为目标变量
df['前一日开盘'] = df['开盘'].shift(1)
df['前一日收盘'] = df['收盘'].shift(1)
df['前二日开盘'] = df['开盘'].shift(2)
df['前二日收盘'] = df['收盘'].shift(2)
df['前三日开盘'] = df['开盘'].shift(3)
df['前三日收盘'] = df['收盘'].shift(3)
# 去除前三日缺失的数据
df = df.dropna()
# 提取输入特征和目标变量
features = df[['成交额', '换手率', '振幅', '前一日开盘', '前一日收盘', '前二日开盘', '前二日收盘', '前三日开盘', '前三日收盘']]
target_open = df['开盘']
target_close = df['收盘']
4. 数据划分和模型训练
将特征数据和目标变量分别划分为训练集和测试集,使用train_test_split()
函数进行划分。然后,创建两个线性回归模型(一个用于预测开盘价,一个用于预测收盘价),并使用训练集对模型进行训练。
# 创建线性回归模型
model_open = LinearRegression()
model_close = LinearRegression()
# 训练模型
model_open.fit(X_train, y_train_open)
model_close.fit(X_train, y_train_close)
5. 预测和评估
使用训练好的模型对测试集进行预测,并计算预测值与实际值之间的均方误差(MSE)作为模型性能的评估指标。
# 预测测试集
y_pred_open = model_open.predict(X_test)
y_pred_close = model_close.predict(X_test)
# 评估模型性能(均方误差)
mse_open = mean_squared_error(y_test_open, y_pred_open)
mse_close = mean_squared_error(y_test_close, y_pred_close)
print('开盘价的均方误差:', mse_open)
print('收盘价的均方误差:', mse_close)
# 使用模型进行预测
last_row = df.iloc[-1]
# 提取最后一行的成交额、换手率和振幅数据以及前三日的开盘价和收盘价
your_new_volume = last_row['成交额']
your_new_turnover = last_row['换手率']
your_new_amplitude = last_row['振幅']
your_new_previous_open = last_row['开盘']
your_new_previous_close = last_row['收盘']
your_new_second_open = last_row['前一日开盘']
your_new_second_close = last_row['前一日收盘']
your_new_third_open = last_row['前二日开盘']
your_new_third_close = last_row['前二日收盘']
# 创建包含最后一行数据的new_data数据框
new_data = pd.DataFrame({
'成交额': [your_new_volume],
'换手率': [your_new_turnover],
'振幅': [your_new_amplitude],
'前一日开盘': [your_new_previous_open],
'前一日收盘': [your_new_previous_close],
'前二日开盘': [your_new_second_open],
'前二日收盘': [your_new_second_close],
'前三日开盘': [your_new_third_open],
'前三日收盘': [your_new_third_close]
})
predicted_open = model_open.predict(new_data)
predicted_close = model_close.predict(new_data)
print('下一日开盘价的预测值:', predicted_open[0])
print('下一日收盘价的预测值:', predicted_close[0])
6. 预测下一日股票价格
当用户点击"预测"按钮时,应用程序使用最新的K线数据,提取最后一天的特征数据,然后使用训练好的模型对下一日的开盘价和收盘价进行预测。
messagebox.showinfo('预测结果', f'下一日开盘价的预测值: {predicted_open[0]}\n下一日收盘价的预测值: {predicted_close[0]}')
三、完整代码
from tkinter import Tk, Label, Entry, Button, messagebox
from urllib.parse import urlencode
import pandas as pd
import requests
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
def gen_secid(rawcode: str) -> str:
# 沪市指数
if rawcode[:3] == '000':
return f'1.{rawcode}'
# 深证指数
if rawcode[:3] == '399':
return f'0.{rawcode}'
# 沪市股票
if rawcode[0] != '6':
return f'0.{rawcode}'
# 深市股票
return f'1.{rawcode}'
def get_k_history(code: str, beg: str, end: str, klt: int = 101, fqt: int = 1) -> pd.DataFrame:
'''
功能获取k线数据
-
'''
EastmoneyKlines = {
'f51': '日期',
'f52': '开盘',
'f53': '收盘',
'f54': '最高',
'f55': '最低',
'f56': '成交量',
'f57': '成交额',
'f58': '振幅',
'f59': '涨跌幅',
'f60': '涨跌额',
'f61': '换手率',
}
EastmoneyHeaders = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko',
'Accept': '*/*',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Referer': 'http://quote.eastmoney.com/center/gridlist.html',
}
fields = list(EastmoneyKlines.keys())
columns = list(EastmoneyKlines.values())
fields2 = ",".join(fields)
secid = gen_secid(code)
params = (
('fields1', 'f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13'),
('fields2', fields2),
('beg', beg),
('end', end),
('rtntype', '6'),
('secid', secid),
('klt', f'{klt}'),
('fqt', f'{fqt}'),
)
params = dict(params)
base_url = 'https://push2his.eastmoney.com/api/qt/stock/kline/get'
url = base_url + '?' + urlencode(params)
json_response: dict = requests.get(url, headers=EastmoneyHeaders).json()
print(url)
data = json_response.get('data')
if data is None:
if secid[0] == '0':
secid = f'1.{code}'
else:
secid = f'0.{code}'
params['secid'] = secid
url = base_url + '?' + urlencode(params)
json_response: dict = requests.get(url, headers=EastmoneyHeaders).json()
data = json_response.get('data')
if data is None:
messagebox.showerror('错误', f'股票代码: {code} 可能有误')
return pd.DataFrame(columns=columns)
klines = data['klines']
rows = []
for _kline in klines:
kline = _kline.split(',')
rows.append(kline)
df = pd.DataFrame(rows, columns=columns)
return df
def fetch_stock_data():
code = code_entry.get()
if not code:
messagebox.showerror('错误', '请输入股票代码')
return
# Get the start date and end date from the date entry widgets
start_date = start_date_entry.get()
end_date = end_date_entry.get()
print(f'正在获取 {code} 从 {start_date} 到 {end_date} 的 k线数据......')
df = get_k_history(code, start_date, end_date)
print(df)
# Generate and display the line chart
def predict_next_day_price():
code = code_entry.get()
if not code:
messagebox.showerror('错误', '请输入股票代码')
return
# Get the start date and end date from the date entry widgets
start_date = start_date_entry.get()
end_date = end_date_entry.get()
print(f'正在获取 {code} 从 {start_date} 到 {end_date} 的 k线数据......')
df = get_k_history(code, start_date, end_date)
if df.empty:
return
# 添加前一日至前三日的开盘价和收盘价作为目标变量
df['前一日开盘'] = df['开盘'].shift(1)
df['前一日收盘'] = df['收盘'].shift(1)
df['前二日开盘'] = df['开盘'].shift(2)
df['前二日收盘'] = df['收盘'].shift(2)
df['前三日开盘'] = df['开盘'].shift(3)
df['前三日收盘'] = df['收盘'].shift(3)
# 去除前三日缺失的数据
df = df.dropna()
# 提取输入特征和目标变量
features = df[['成交额', '换手率', '振幅', '前一日开盘', '前一日收盘', '前二日开盘', '前二日收盘', '前三日开盘', '前三日收盘']]
target_open = df['开盘']
target_close = df['收盘']
# 划分训练集和测试集
X_train, X_test, y_train_open, y_test_open, y_train_close, y_test_close = train_test_split(
features, target_open, target_close, test_size=0.2, random_state=42
)
# 创建线性回归模型
model_open = LinearRegression()
model_close = LinearRegression()
# 训练模型
model_open.fit(X_train, y_train_open)
model_close.fit(X_train, y_train_close)
# 预测测试集
y_pred_open = model_open.predict(X_test)
y_pred_close = model_close.predict(X_test)
# 评估模型性能(均方误差)
mse_open = mean_squared_error(y_test_open, y_pred_open)
mse_close = mean_squared_error(y_test_close, y_pred_close)
print('开盘价的均方误差:', mse_open)
print('收盘价的均方误差:', mse_close)
# 使用模型进行预测
last_row = df.iloc[-1]
# 提取最后一行的成交额、换手率和振幅数据以及前三日的开盘价和收盘价
your_new_volume = last_row['成交额']
your_new_turnover = last_row['换手率']
your_new_amplitude = last_row['振幅']
your_new_previous_open = last_row['开盘']
your_new_previous_close = last_row['收盘']
your_new_second_open = last_row['前一日开盘']
your_new_second_close = last_row['前一日收盘']
your_new_third_open = last_row['前二日开盘']
your_new_third_close = last_row['前二日收盘']
# 创建包含最后一行数据的new_data数据框
new_data = pd.DataFrame({
'成交额': [your_new_volume],
'换手率': [your_new_turnover],
'振幅': [your_new_amplitude],
'前一日开盘': [your_new_previous_open],
'前一日收盘': [your_new_previous_close],
'前二日开盘': [your_new_second_open],
'前二日收盘': [your_new_second_close],
'前三日开盘': [your_new_third_open],
'前三日收盘': [your_new_third_close]
})
predicted_open = model_open.predict(new_data)
predicted_close = model_close.predict(new_data)
print('下一日开盘价的预测值:', predicted_open[0])
print('下一日收盘价的预测值:', predicted_close[0])
messagebox.showinfo('预测结果', f'下一日开盘价的预测值: {predicted_open[0]}\n下一日收盘价的预测值: {predicted_close[0]}')
# 创建主窗口
root = Tk()
root.title('股票预测')
root.geometry('400x300')
# 股票代码标签和输入框
code_label = Label(root, text='股票代码:')
code_label.pack()
code_entry = Entry(root)
code_entry.pack()
# 开始日期标签和输入框
start_date_label = Label(root, text='开始日期:')
start_date_label.pack()
start_date_entry = Entry(root)
start_date_entry.pack()
# 结束日期标签和输入框
end_date_label = Label(root, text='结束日期:')
end_date_label.pack()
end_date_entry = Entry(root)
end_date_entry.pack()
# 获取数据按钮
fetch_data_button = Button(root, text='获取数据', command=fetch_stock_data)
fetch_data_button.pack()
# 预测按钮
predict_button = Button(root, text='预测', command=predict_next_day_price)
predict_button.pack()
# 运行主窗口的消息循环
root.mainloop()
请注意,这只是一个简单的示例应用程序,用于演示如何使用SMA指标和线性回归模型进行股票价格预测。实际应用中,你可能需要根据自己的需求进行修改和扩展,例如添加更多的特征、尝试其他的机器学习模型、优化界面和交互等。
如有共同爱好,可以加QQ:2388627579互相交流!