Python项目源码38:模拟炒股系统2.0(tkinter+Json)

B站影视 电影资讯 2025-03-18 17:05 1

摘要:# -*- coding: utf-8 -*-# @Author : 小红牛#, messageboxclass StockTradingGUI: def __init__(self, root): self.root = root self.root.tit

主要设计说明:该版本提供了接近专业交易软件的界面体验,同时保持了代码的简洁性和可扩展性,若要用于股票交易模拟教学或个人投资练习,还需要接入真实的股票交易数据,以下源码中的数据虚拟模拟随机生成的数据。

1.界面布局重构:将行情和持仓并排显示在面板中,持仓使用带标题的LabelFrame包裹,持仓Treeview添加汇总行并设置不同背景色。

2.持仓信息实时显示:移除单独的"显示持仓"按钮,持仓信息与行情同步刷新(每3秒),自动颜色标记盈利(红色)/亏损(绿色),增加了持仓市值的实时计算和显示,自动计算并显示总浮动盈亏。

3.显示优化:所有面板使用LabelFrame添加标题,交易记录显示框添加标题,持仓表格自动计算并显示总盈亏。

4.自动更新机制:持仓数据随价格波动实时更新,买卖操作后立即刷新持仓显示,汇总行使用不同背景色突出显示。

5.新界面特点:实时行情和持仓信息并排显示,持仓信息包含详细成本和盈亏计算,自动汇总显示总浮动盈亏,所有数据实时同步更新,界面布局更加紧凑合理。

6.操作说明:初始默认资金500万,可自由修改。持仓信息会随价格波动自动更新,买卖操作后持仓立即刷新,总盈亏显示在持仓表格底部,其他操作方式保持不变。

↓ 完整源码如下 ↓

# -*- coding: utf-8 -*-# @Author : 小红牛#, messageboxclass StockTradingGUI: def __init__(self, root): self.root = root self.root.title("股票交易模拟系统2.0") self.data_file = 'trading_data.json' # 初始化数据 self.cash = 5000000 self.positions = {} self.transactions = self.stock_prices = {} self.load_data # 创建主界面 self.create_widgets self.update_display self.start_auto_update def create_widgets(self): # 配置样式 style = ttk.Style style.configure("Treeview.Heading", font=('微软雅黑', 10)) style.configure("Treeview", font=('微软雅黑', 9), rowheight=25) style.map("Treeview", background=[('selected', '#0078d7')], foreground=[('selected', 'white')]) # 主框架 main_frame = ttk.Frame(self.root, padding=10) main_frame.pack(fill=tk.BOTH, expand=True) # 资金显示 self.cash_label = ttk.Label(main_frame, text="可用资金:", font=('Arial', 12)) self.cash_label.grid(row=0, column=0, columnspan=2, sticky=tk.W) # 操作按钮 btn_frame = ttk.Frame(main_frame) btn_frame.grid(row=1, column=0, columnspan=2, pady=10) ttk.Button(btn_frame, text="买入股票", command=self.show_buy_window).grid(row=0, column=0, padx=5) ttk.Button(btn_frame, text="卖出股票", command=self.show_sell_window).grid(row=0, column=1, padx=5) ttk.Button(btn_frame, text="手动刷新", command=self.update_prices).grid(row=0, column=2, padx=5) ttk.Button(btn_frame, text="盈亏统计", command=self.show_profit).grid(row=0, column=3, padx=5) # 行情和持仓面板 panel_frame = ttk.Frame(main_frame) panel_frame.grid(row=2, column=0, columnspan=2, sticky=tk.NSEW) # 实时行情面板 market_frame = ttk.LabelFrame(panel_frame, text="实时模拟行情", padding=10) market_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) self.market_tree = ttk.Treeview(market_frame, columns=('代码', '价格'), show='headings', height=8) self.market_tree.heading('代码', text='代码', anchor=tk.CENTER) self.market_tree.heading('价格', text='价格', anchor=tk.CENTER) self.market_tree.column('代码', width=120, anchor=tk.W, minwidth=100) self.market_tree.column('价格', width=100, anchor=tk.E, minwidth=80) self.market_tree.pack(fill=tk.BOTH, expand=True) # 持仓信息面板 position_frame = ttk.LabelFrame(panel_frame, text="当前持仓", padding=10) position_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True) self.position_tree = ttk.Treeview(position_frame, columns=('代码', '数量', '成本价', '现价', '盈亏', '持仓市值'), show='headings', height=8) columns_config = { '代码': {'width': 120, 'anchor': tk.W, 'minwidth': 100}, '数量': {'width': 80, 'anchor': tk.E, 'minwidth': 60}, '成本价': {'width': 100, 'anchor': tk.E, 'minwidth': 80}, '现价': {'width': 100, 'anchor': tk.E, 'minwidth': 80}, '盈亏': {'width': 120, 'anchor': tk.E, 'minwidth': 100}, '持仓市值': {'width': 110, 'anchor': tk.E, 'minwidth': 100} # 新增列 } for col, config in columns_config.items: self.position_tree.heading(col, text=col, anchor=tk.CENTER) self.position_tree.column(col, **config) self.position_tree.pack(fill=tk.BOTH, expand=True) # 交易记录面板 txn_frame = ttk.LabelFrame(main_frame, text="最近交易记录", padding=10) txn_frame.grid(row=3, column=0, columnspan=2, sticky=tk.EW) self.transaction_text = tk.Text(txn_frame, height=5, width=80) self.transaction_text.pack(fill=tk.BOTH) # 退出按钮 ttk.Button(main_frame, text="退出模拟系统", command=self.on_exit).grid(row=4, column=0, columnspan=2, pady=10) def load_data(self): if os.path.exists(self.data_file): with open(self.data_file, 'r') as f: data = json.load(f) self.cash = data['cash'] self.positions = data['positions'] self.transactions = data['transactions'] self.stock_prices = data['stock_prices'] def save_data(self): data = { 'cash': self.cash, 'positions': self.positions, 'transactions': self.transactions, 'stock_prices': self.stock_prices } with open(self.data_file, 'w') as f: json.dump(data, f, indent=4) def start_auto_update(self): self.auto_update def auto_update(self): self.update_prices self.root.after(3000, self.auto_update) def update_prices(self): try: for code in self.stock_prices: current = self.stock_prices[code] change = current * random.uniform(-0.05, 0.05) self.stock_prices[code] = round(current + change, 2) self.update_display except Exception as e: print(f"价格更新出错:{str(e)}") def update_display(self): # 更新资金显示 self.cash_label.config(text=f"可用资金:{self.cash:.2f}元") # 更新行情显示 self.market_tree.delete(*self.market_tree.get_children) for code, price in self.stock_prices.items: self.market_tree.insert('', 'end', values=(code, f"{price:.2f}")) # 更新持仓显示 self.position_tree.delete(*self.position_tree.get_children) total_pnl = 0 total_value = 0 # 新增总市值统计 for code, pos in self.positions.items: curr = self.stock_prices.get(code, 0) cost = pos['cost_price'] shares = pos['shares'] pnl = (curr - cost) * shares value = cost * shares # 计算持仓市值 total_pnl += pnl total_value += value # 累加总市值 tag = 'profit' if pnl >= 0 else 'loss' self.position_tree.insert('', 'end', values=( code, shares, f"{cost:.2f}", f"{curr:.2f}", f"{pnl:+.2f}", f"{value:.2f}" # 新增市值显示 ), tags=(tag,)) # 更新汇总行 self.position_tree.insert('', 'end', values=( "持仓总计:", "", "", f"{total_value:.2f}", # 显示总市值 "", f"{total_pnl:+.2f}" ), tags=('total',)) # 配置样式标签 self.position_tree.tag_configure('profit', foreground='#ff0000') self.position_tree.tag_configure('loss', foreground='#009900') self.position_tree.tag_configure('total', background='#f0f0ff', font=('微软雅黑', 9, 'bold')) # 更新交易记录 self.transaction_text.delete(1.0, tk.END) for trans in self.transactions[-5:]: self.transaction_text.insert(tk.END, f"{trans['time']} {trans['type']} {trans['code']} {trans['shares']}股,价格 {trans['price']:.2f}\n") def show_buy_window(self): self.trade_window('buy') def show_sell_window(self): self.trade_window('sell') def trade_window(self, trade_type): window = tk.Toplevel(self.root) window.title("股票买入" if trade_type == 'buy' else "股票卖出") ttk.Label(window, text="股票代码:").grid(row=0, column=0, padx=5, pady=5) code_entry = ttk.Entry(window) code_entry.grid(row=0, column=1) ttk.Label(window, text="交易数量:").grid(row=1, column=0) shares_entry = ttk.Entry(window) shares_entry.grid(row=1, column=1) def execute_trade: code = code_entry.get.upper try: shares = int(shares_entry.get) if trade_type == 'buy': success = self.buy(code, shares) else: success = self.sell(code, shares) if success: self.update_display window.destroy except ValueError: messagebox.showerror("输入错误", "请输入有效的整数数量") ttk.Button(window, text="确认交易", command=execute_trade).grid(row=2, columnspan=2, pady=10) def buy(self, code, shares): if code not in self.stock_prices: self.stock_prices[code] = round(random.uniform(10, 200), 2) price = self.stock_prices[code] total_cost = price * shares if total_cost > self.cash: messagebox.showerror("交易失败", "可用资金不足!") return False self.cash -= total_cost if code in self.positions: pos = self.positions[code] new_shares = pos['shares'] + shares new_cost = (pos['shares'] * pos['cost_price'] + total_cost) / new_shares self.positions[code] = { 'shares': new_shares, 'cost_price': round(new_cost, 2) } else: self.positions[code] = { 'shares': shares, 'cost_price': price } self.transactions.append({ 'time': datetime.datetime.now.strftime('%Y-%m-%d %H:%M:%S'), 'type': 'buy', 'code': code, 'price': price, 'shares': shares }) messagebox.showinfo("交易成功", f"成功买入 {shares} 股 {code} @ {price:.2f}") return True def sell(self, code, shares): if code not in self.positions: messagebox.showerror("交易失败", "未持有该股票!") return False pos = self.positions[code] if shares > pos['shares']: messagebox.showerror("交易失败", "卖出数量超过持仓!") return False price = self.stock_prices[code] total = price * shares self.cash += total pos['shares'] -= shares if pos['shares'] == 0: del self.positions[code] self.transactions.append({ 'time': datetime.datetime.now.strftime('%Y-%m-%d %H:%M:%S'), 'type': 'sell', 'code': code, 'price': price, 'shares': shares, 'cost_price': pos['cost_price'] }) messagebox.showinfo("交易成功", f"成功卖出 {shares} 股 {code} @ {price:.2f}") return True def show_profit(self): realized = sum( (t['price'] - t['cost_price']) * t['shares'] for t in self.transactions if t['type'] == 'sell' ) floating = sum( (self.stock_prices.get(code, 0) - pos['cost_price']) * pos['shares'] for code, pos in self.positions.items ) messagebox.showinfo("盈亏统计", f"已实现盈亏:{realized:+.2f}\n" f"浮动盈亏:{floating:+.2f}\n" f"总盈亏:{realized + floating:+.2f}") def on_exit(self): self.save_data self.root.destroyif __name__ == '__main__': root = tk.Tk app = StockTradingGUI(root) root.mainloop

来源:散文随风想

相关推荐