股票近期跌幅分析GUI

import sys
import io
import pandas as pd
import matplotlib.pyplot as plta
from datetime import datetime, timedelta
import tushare as ts
import tkinter as tk
from tkinter import ttk, messagebox

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

class StockAnalysisApp:
    def __init__(self, root):
        self.root = root
        self.root.title("股票分析系统")
        self.root.geometry("600x500")
        
        # 初始化参数
        self.stock_code = '002108'
        self.days = 30
        self.ma_periods = [5, 10, 20]
        
        self.create_widgets()
    
    def create_widgets(self):
        # 股票代码输入
        ttk.Label(self.root, text="股票代码:").pack(pady=5)
        self.code_entry = ttk.Entry(self.root)
        self.code_entry.insert(0, self.stock_code)
        self.code_entry.pack(pady=5)
        
        # 天数输入
        ttk.Label(self.root, text="分析天数:").pack(pady=5)
        self.days_entry = ttk.Entry(self.root)
        self.days_entry.insert(0, str(self.days))
        self.days_entry.pack(pady=5)
        
        # 均线周期输入
        ttk.Label(self.root, text="均线周期(逗号分隔):").pack(pady=5)
        self.ma_entry = ttk.Entry(self.root)
        self.ma_entry.insert(0, ','.join(map(str, self.ma_periods)))
        self.ma_entry.pack(pady=5)
        
        # 运行按钮
        self.run_btn = ttk.Button(self.root, text="运行分析", command=self.run_analysis)
        self.run_btn.pack(pady=20)
        
        # 结果显示区域
        ttk.Label(self.root, text="分析结果:").pack(pady=5)
        self.result_text = tk.Text(self.root, height=10, width=70)
        self.result_text.pack(pady=5)
    
    def run_analysis(self):
        try:
            # 获取参数
            self.stock_code = self.code_entry.get().strip()
            self.days = int(self.days_entry.get().strip())
            self.ma_periods = list(map(int, [x.strip() for x in self.ma_entry.get().strip().split(',')]))
            
            # 获取数据
            stock_data = self.get_stock_data()
            
            if stock_data is not None:
                # 计算均线
                for period in self.ma_periods:
                    stock_data[f'MA{period}'] = stock_data['close'].rolling(window=period).mean()
                
                # 计算跌幅
                first_close = stock_data['close'].iloc[0]
                last_close = stock_data['close'].iloc[-1]
                total_drop = ((last_close - first_close) / first_close) * 100
                
                max_daily_drop = stock_data['Daily_Return'].min() * 100
                max_drop_date = stock_data['Daily_Return'].idxmin().strftime('%Y-%m-%d')
                
                # 显示结果
                result = f"""
股票{self.stock_code}分析结果:
========================
总跌幅: {total_drop:.2f}%
最大单日跌幅: {max_daily_drop:.2f}% (日期: {max_drop_date})
起始价格: {first_close:.2f}元
结束价格: {last_close:.2f}元
分析天数: {self.days}天
均线周期: {', '.join(map(str, self.ma_periods))}
                """
                self.result_text.delete(1.0, tk.END)
                self.result_text.insert(tk.END, result)
                
                # 保存结果到文件
                self.save_result_to_file(result)
                
                # 绘制图表
                self.plot_chart(stock_data)
                
        except Exception as e:
            messagebox.showerror("错误", f"运行出错: {str(e)}")
    
    def save_result_to_file(self, result):
        try:
            # 保存结果到文本文件
            filename = f'股票{self.stock_code}_分析结果.txt'
            with open(filename, 'w', encoding='utf-8') as f:
                f.write(result)
            messagebox.showinfo("成功", f"分析结果已保存到 '{filename}' 文件")
        except Exception as e:
            messagebox.showerror("错误", f"保存文件失败: {str(e)}")
    
    def get_stock_data(self):
        try:
            end_date = datetime.now()
            start_date = end_date - timedelta(days=self.days)
            start_str = start_date.strftime('%Y%m%d')
            end_str = end_date.strftime('%Y%m%d')
            
            ts.set_token('866b8c22a26277af04f65c453d61300c740217a4ee2e57b33c7cd199_aubb')
            pro = ts.pro_api()
            
            # 根据股票代码判断交易所
            if self.stock_code.startswith('6'):
                ts_code_full = self.stock_code + '.SH'
            else:
                ts_code_full = self.stock_code + '.SZ'
            
            stock_data = pro.daily(ts_code=ts_code_full, start_date=start_str, end_date=end_str)
            
            if stock_data.empty:
                messagebox.showwarning("警告", "无法获取股票数据,请检查股票代码是否正确")
                return None
            
            stock_data['trade_date'] = pd.to_datetime(stock_data['trade_date'])
            stock_data = stock_data.sort_values('trade_date')
            stock_data.set_index('trade_date', inplace=True)
            stock_data['Daily_Return'] = stock_data['close'].pct_change()
            
            return stock_data
            
        except Exception as e:
            messagebox.showerror("错误", f"获取数据失败: {str(e)}")
            return None
    
    def plot_chart(self, stock_data):
        plt.figure(figsize=(14, 8))
        
        # 绘制收盘价
        plt.plot(stock_data.index, stock_data['close'], label='收盘价', color='blue', linewidth=2)
        
        # 绘制均线
        colors = ['red', 'green', 'orange', 'purple', 'brown']
        for i, period in enumerate(self.ma_periods):
            plt.plot(stock_data.index, stock_data[f'MA{period}'], 
                    label=f'MA{period}', color=colors[i % len(colors)], linewidth=1.5)
        
        plt.title(f'股票{self.stock_code}价格走势及均线', fontsize=16)
        plt.xlabel('日期', fontsize=12)
        plt.ylabel('价格 (元)', fontsize=12)
        plt.grid(True, alpha=0.3)
        plt.legend(fontsize=10)
        plt.tight_layout()
        
        chart_path = f'股票{self.stock_code}_走势图_均线版.png'
        plt.savefig(chart_path, dpi=150)
        plt.show()

if __name__ == "__main__":
    root = tk.Tk()
    app = StockAnalysisApp(root)
    root.mainloop()

股票601688分析结果:

总跌幅: -27.43%
最大单日跌幅: -5.04% (日期: 2026-01-08)
起始价格: 24.35元
结束价格: 17.67元
分析天数: 90天
均线周期: 5, 10, 20