{"id":7132,"date":"2026-04-05T11:14:41","date_gmt":"2026-04-05T03:14:41","guid":{"rendered":"http:\/\/192.168.1.29\/?p=7132"},"modified":"2026-04-05T11:40:52","modified_gmt":"2026-04-05T03:40:52","slug":"%e8%82%a1%e7%a5%a8%e8%bf%91%e6%9c%9f%e8%b7%8c%e5%b9%85%e5%88%86%e6%9e%90gui","status":"publish","type":"post","link":"http:\/\/e9vh83du.ipyingshe.net:5347\/?p=7132","title":{"rendered":"\u80a1\u7968\u8fd1\u671f\u8dcc\u5e45\u5206\u6790GUI"},"content":{"rendered":"\n<pre class=\"wp-block-code\"><code>import sys\nimport io\nimport pandas as pd\nimport matplotlib.pyplot as plta\nfrom datetime import datetime, timedelta\nimport tushare as ts\nimport tkinter as tk\nfrom tkinter import ttk, messagebox\n\n# \u8bbe\u7f6e\u4e2d\u6587\u5b57\u4f53\nplt.rcParams&#91;'font.sans-serif'] = &#91;'SimHei']\nplt.rcParams&#91;'axes.unicode_minus'] = False\n\nclass StockAnalysisApp:\n    def __init__(self, root):\n        self.root = root\n        self.root.title(\"\u80a1\u7968\u5206\u6790\u7cfb\u7edf\")\n        self.root.geometry(\"600x500\")\n        \n        # \u521d\u59cb\u5316\u53c2\u6570\n        self.stock_code = '002108'\n        self.days = 30\n        self.ma_periods = &#91;5, 10, 20]\n        \n        self.create_widgets()\n    \n    def create_widgets(self):\n        # \u80a1\u7968\u4ee3\u7801\u8f93\u5165\n        ttk.Label(self.root, text=\"\u80a1\u7968\u4ee3\u7801:\").pack(pady=5)\n        self.code_entry = ttk.Entry(self.root)\n        self.code_entry.insert(0, self.stock_code)\n        self.code_entry.pack(pady=5)\n        \n        # \u5929\u6570\u8f93\u5165\n        ttk.Label(self.root, text=\"\u5206\u6790\u5929\u6570:\").pack(pady=5)\n        self.days_entry = ttk.Entry(self.root)\n        self.days_entry.insert(0, str(self.days))\n        self.days_entry.pack(pady=5)\n        \n        # \u5747\u7ebf\u5468\u671f\u8f93\u5165\n        ttk.Label(self.root, text=\"\u5747\u7ebf\u5468\u671f\uff08\u9017\u53f7\u5206\u9694\uff09:\").pack(pady=5)\n        self.ma_entry = ttk.Entry(self.root)\n        self.ma_entry.insert(0, ','.join(map(str, self.ma_periods)))\n        self.ma_entry.pack(pady=5)\n        \n        # \u8fd0\u884c\u6309\u94ae\n        self.run_btn = ttk.Button(self.root, text=\"\u8fd0\u884c\u5206\u6790\", command=self.run_analysis)\n        self.run_btn.pack(pady=20)\n        \n        # \u7ed3\u679c\u663e\u793a\u533a\u57df\n        ttk.Label(self.root, text=\"\u5206\u6790\u7ed3\u679c:\").pack(pady=5)\n        self.result_text = tk.Text(self.root, height=10, width=70)\n        self.result_text.pack(pady=5)\n    \n    def run_analysis(self):\n        try:\n            # \u83b7\u53d6\u53c2\u6570\n            self.stock_code = self.code_entry.get().strip()\n            self.days = int(self.days_entry.get().strip())\n            self.ma_periods = list(map(int, &#91;x.strip() for x in self.ma_entry.get().strip().split(',')]))\n            \n            # \u83b7\u53d6\u6570\u636e\n            stock_data = self.get_stock_data()\n            \n            if stock_data is not None:\n                # \u8ba1\u7b97\u5747\u7ebf\n                for period in self.ma_periods:\n                    stock_data&#91;f'MA{period}'] = stock_data&#91;'close'].rolling(window=period).mean()\n                \n                # \u8ba1\u7b97\u8dcc\u5e45\n                first_close = stock_data&#91;'close'].iloc&#91;0]\n                last_close = stock_data&#91;'close'].iloc&#91;-1]\n                total_drop = ((last_close - first_close) \/ first_close) * 100\n                \n                max_daily_drop = stock_data&#91;'Daily_Return'].min() * 100\n                max_drop_date = stock_data&#91;'Daily_Return'].idxmin().strftime('%Y-%m-%d')\n                \n                # \u663e\u793a\u7ed3\u679c\n                result = f\"\"\"\n\u80a1\u7968{self.stock_code}\u5206\u6790\u7ed3\u679c\uff1a\n========================\n\u603b\u8dcc\u5e45: {total_drop:.2f}%\n\u6700\u5927\u5355\u65e5\u8dcc\u5e45: {max_daily_drop:.2f}% (\u65e5\u671f: {max_drop_date})\n\u8d77\u59cb\u4ef7\u683c: {first_close:.2f}\u5143\n\u7ed3\u675f\u4ef7\u683c: {last_close:.2f}\u5143\n\u5206\u6790\u5929\u6570: {self.days}\u5929\n\u5747\u7ebf\u5468\u671f: {', '.join(map(str, self.ma_periods))}\n                \"\"\"\n                self.result_text.delete(1.0, tk.END)\n                self.result_text.insert(tk.END, result)\n                \n                # \u4fdd\u5b58\u7ed3\u679c\u5230\u6587\u4ef6\n                self.save_result_to_file(result)\n                \n                # \u7ed8\u5236\u56fe\u8868\n                self.plot_chart(stock_data)\n                \n        except Exception as e:\n            messagebox.showerror(\"\u9519\u8bef\", f\"\u8fd0\u884c\u51fa\u9519: {str(e)}\")\n    \n    def save_result_to_file(self, result):\n        try:\n            # \u4fdd\u5b58\u7ed3\u679c\u5230\u6587\u672c\u6587\u4ef6\n            filename = f'\u80a1\u7968{self.stock_code}_\u5206\u6790\u7ed3\u679c.txt'\n            with open(filename, 'w', encoding='utf-8') as f:\n                f.write(result)\n            messagebox.showinfo(\"\u6210\u529f\", f\"\u5206\u6790\u7ed3\u679c\u5df2\u4fdd\u5b58\u5230 '{filename}' \u6587\u4ef6\")\n        except Exception as e:\n            messagebox.showerror(\"\u9519\u8bef\", f\"\u4fdd\u5b58\u6587\u4ef6\u5931\u8d25: {str(e)}\")\n    \n    def get_stock_data(self):\n        try:\n            end_date = datetime.now()\n            start_date = end_date - timedelta(days=self.days)\n            start_str = start_date.strftime('%Y%m%d')\n            end_str = end_date.strftime('%Y%m%d')\n            \n            ts.set_token('866b8c22a26277af04f65c453d61300c740217a4ee2e57b33c7cd199_aubb')\n            pro = ts.pro_api()\n            \n            # \u6839\u636e\u80a1\u7968\u4ee3\u7801\u5224\u65ad\u4ea4\u6613\u6240\n            if self.stock_code.startswith('6'):\n                ts_code_full = self.stock_code + '.SH'\n            else:\n                ts_code_full = self.stock_code + '.SZ'\n            \n            stock_data = pro.daily(ts_code=ts_code_full, start_date=start_str, end_date=end_str)\n            \n            if stock_data.empty:\n                messagebox.showwarning(\"\u8b66\u544a\", \"\u65e0\u6cd5\u83b7\u53d6\u80a1\u7968\u6570\u636e\uff0c\u8bf7\u68c0\u67e5\u80a1\u7968\u4ee3\u7801\u662f\u5426\u6b63\u786e\")\n                return None\n            \n            stock_data&#91;'trade_date'] = pd.to_datetime(stock_data&#91;'trade_date'])\n            stock_data = stock_data.sort_values('trade_date')\n            stock_data.set_index('trade_date', inplace=True)\n            stock_data&#91;'Daily_Return'] = stock_data&#91;'close'].pct_change()\n            \n            return stock_data\n            \n        except Exception as e:\n            messagebox.showerror(\"\u9519\u8bef\", f\"\u83b7\u53d6\u6570\u636e\u5931\u8d25: {str(e)}\")\n            return None\n    \n    def plot_chart(self, stock_data):\n        plt.figure(figsize=(14, 8))\n        \n        # \u7ed8\u5236\u6536\u76d8\u4ef7\n        plt.plot(stock_data.index, stock_data&#91;'close'], label='\u6536\u76d8\u4ef7', color='blue', linewidth=2)\n        \n        # \u7ed8\u5236\u5747\u7ebf\n        colors = &#91;'red', 'green', 'orange', 'purple', 'brown']\n        for i, period in enumerate(self.ma_periods):\n            plt.plot(stock_data.index, stock_data&#91;f'MA{period}'], \n                    label=f'MA{period}', color=colors&#91;i % len(colors)], linewidth=1.5)\n        \n        plt.title(f'\u80a1\u7968{self.stock_code}\u4ef7\u683c\u8d70\u52bf\u53ca\u5747\u7ebf', fontsize=16)\n        plt.xlabel('\u65e5\u671f', fontsize=12)\n        plt.ylabel('\u4ef7\u683c (\u5143)', fontsize=12)\n        plt.grid(True, alpha=0.3)\n        plt.legend(fontsize=10)\n        plt.tight_layout()\n        \n        chart_path = f'\u80a1\u7968{self.stock_code}_\u8d70\u52bf\u56fe_\u5747\u7ebf\u7248.png'\n        plt.savefig(chart_path, dpi=150)\n        plt.show()\n\nif __name__ == \"__main__\":\n    root = tk.Tk()\n    app = StockAnalysisApp(root)\n    root.mainloop()<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"904\" src=\"http:\/\/192.168.1.29\/wp-content\/uploads\/2026\/04\/\u80a1\u7968\u8d70\u52bf_20260405110037_4_7-1024x904.png\" alt=\"\" class=\"wp-image-7137\" srcset=\"http:\/\/e9vh83du.ipyingshe.net:5347\/wp-content\/uploads\/2026\/04\/\u80a1\u7968\u8d70\u52bf_20260405110037_4_7-1024x904.png 1024w, http:\/\/e9vh83du.ipyingshe.net:5347\/wp-content\/uploads\/2026\/04\/\u80a1\u7968\u8d70\u52bf_20260405110037_4_7-300x265.png 300w, http:\/\/e9vh83du.ipyingshe.net:5347\/wp-content\/uploads\/2026\/04\/\u80a1\u7968\u8d70\u52bf_20260405110037_4_7-768x678.png 768w, http:\/\/e9vh83du.ipyingshe.net:5347\/wp-content\/uploads\/2026\/04\/\u80a1\u7968\u8d70\u52bf_20260405110037_4_7.png 1055w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h1 class=\"wp-block-heading\">\u80a1\u7968601688\u5206\u6790\u7ed3\u679c\uff1a<\/h1>\n\n\n\n<p>\u603b\u8dcc\u5e45: -27.43%<br>\u6700\u5927\u5355\u65e5\u8dcc\u5e45: -5.04% (\u65e5\u671f: 2026-01-08)<br>\u8d77\u59cb\u4ef7\u683c: 24.35\u5143<br>\u7ed3\u675f\u4ef7\u683c: 17.67\u5143<br>\u5206\u6790\u5929\u6570: 90\u5929<br>\u5747\u7ebf\u5468\u671f: 5, 10, 20<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"634\" src=\"http:\/\/192.168.1.29\/wp-content\/uploads\/2026\/04\/\u80a1\u7968601688\u534e\u6cf0\u8bc1\u5238-1024x634.png\" alt=\"\" class=\"wp-image-7134\" srcset=\"http:\/\/e9vh83du.ipyingshe.net:5347\/wp-content\/uploads\/2026\/04\/\u80a1\u7968601688\u534e\u6cf0\u8bc1\u5238-1024x634.png 1024w, http:\/\/e9vh83du.ipyingshe.net:5347\/wp-content\/uploads\/2026\/04\/\u80a1\u7968601688\u534e\u6cf0\u8bc1\u5238-300x186.png 300w, http:\/\/e9vh83du.ipyingshe.net:5347\/wp-content\/uploads\/2026\/04\/\u80a1\u7968601688\u534e\u6cf0\u8bc1\u5238-768x475.png 768w, http:\/\/e9vh83du.ipyingshe.net:5347\/wp-content\/uploads\/2026\/04\/\u80a1\u7968601688\u534e\u6cf0\u8bc1\u5238-1536x950.png 1536w, http:\/\/e9vh83du.ipyingshe.net:5347\/wp-content\/uploads\/2026\/04\/\u80a1\u7968601688\u534e\u6cf0\u8bc1\u5238-2048x1267.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u80a1\u7968601688\u5206\u6790\u7ed3\u679c\uff1a \u603b\u8dcc\u5e45: -27.43%\u6700\u5927\u5355\u65e5\u8dcc\u5e45: -5.04% <span class=\"readmore\"><a href=\"http:\/\/e9vh83du.ipyingshe.net:5347\/?p=7132\">Continue Reading<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[24],"tags":[],"class_list":["post-7132","post","type-post","status-publish","format-standard","hentry","category-24"],"_links":{"self":[{"href":"http:\/\/e9vh83du.ipyingshe.net:5347\/index.php?rest_route=\/wp\/v2\/posts\/7132","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/e9vh83du.ipyingshe.net:5347\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/e9vh83du.ipyingshe.net:5347\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/e9vh83du.ipyingshe.net:5347\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/e9vh83du.ipyingshe.net:5347\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=7132"}],"version-history":[{"count":2,"href":"http:\/\/e9vh83du.ipyingshe.net:5347\/index.php?rest_route=\/wp\/v2\/posts\/7132\/revisions"}],"predecessor-version":[{"id":7138,"href":"http:\/\/e9vh83du.ipyingshe.net:5347\/index.php?rest_route=\/wp\/v2\/posts\/7132\/revisions\/7138"}],"wp:attachment":[{"href":"http:\/\/e9vh83du.ipyingshe.net:5347\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=7132"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/e9vh83du.ipyingshe.net:5347\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=7132"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/e9vh83du.ipyingshe.net:5347\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=7132"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}