币安期货Tkinter工具:获取最新价格并计算下单量实现多空委托
币安期货量化工具问题修复与功能完善
核心问题梳理
- 初始加载时未选中交易对就发起价格请求,导致API调用失败
- 最新价格仅显示在标签中,未存储为可用于计算的变量
- 未实现
实际下单量=输入金额/最新价格的核心计算逻辑 - 缺乏输入验证与错误处理,容易触发无效订单或程序崩溃
修复后完整代码
from tkinter import * import os import tkinter from tkinter import ttk from tkinter import messagebox from binance.client import Client #### API KEYS api_key = os.environ.get('binance_api') api_secret = os.environ.get('binance_secret') client = Client(api_key, api_secret) # 全局变量存储最新价格 latest_price = 0.0 # 界面初始化 root = Tk() root.geometry('350x350') root.title("币安期货市价下单工具") l = Label(root, text="MARKET ORDER") l.config(font=("Arial", 20)) l.pack(pady=10) # 交易对选择栏 l = Label(root, text="选择USDT交易对") l.config(font=("Arial", 10)) l.pack() exchange_info = client.futures_exchange_info() usdt_pairs = [s['symbol'] for s in exchange_info['symbols'] if 'USDT' in s['symbol']] def search(event): value = event.widget.get() if value == '': combo_box['values'] = usdt_pairs else: data = [item for item in usdt_pairs if value.lower() in item.lower()] combo_box['values'] = data combo_box = ttk.Combobox(root, value=usdt_pairs, width=25) combo_box.set('') combo_box.pack(pady=5) combo_box.bind('<KeyRelease>', search) # 价格获取与更新 def show_ticker_info(event=None): global latest_price selected_symbol = combo_box.get() if selected_symbol: try: # 移除无效的timeframe参数,正确调用期货ticker接口 ticker_info = client.futures_ticker(symbol=selected_symbol) latest_price = float(ticker_info['lastPrice']) ticker_text.config(text=f"最新价格: {latest_price:.4f} USDT") except Exception as e: ticker_text.config(text=f"价格获取失败: {str(e)}") # 每隔1秒更新一次价格,避免请求过于频繁 root.after(1000, show_ticker_info) ticker_text = Label(root, text="请选择交易对查看价格", font=("Arial", 10)) ticker_text.pack(pady=5) combo_box.bind("<<ComboboxSelected>>", show_ticker_info) # 启动价格更新循环 root.after(1000, show_ticker_info) # 金额输入栏 l = Label(root, text="输入下单金额(USDT)") l.config(font=("Arial", 10)) l.pack(pady=5) qty_entry = Entry(root, width=20) qty_entry.pack() # 辅助函数:获取交易对的数量步长 def get_quantity_step(symbol): for s in exchange_info['symbols']: if s['symbol'] == symbol: for filter in s['filters']: if filter['filterType'] == 'LOT_SIZE': return float(filter['stepSize']) return 0.01 # 默认步长 # 卖单按钮逻辑 def buttonFunction(): global latest_price selected_symbol = combo_box.get() input_amount_str = qty_entry.get() # 输入验证 if not selected_symbol: messagebox.showerror("错误", "请先选择交易对") return if not input_amount_str.replace('.', '', 1).isdigit(): messagebox.showerror("错误", "请输入有效的数字金额") return if latest_price <= 0: messagebox.showerror("错误", "未获取到有效价格,请检查交易对选择") return input_amount = float(input_amount_str) # 计算实际下单量 raw_qty = input_amount / latest_price # 获取币安要求的数量步长并调整精度 step_size = get_quantity_step(selected_symbol) qty = round(raw_qty / step_size) * step_size try: order = client.futures_create_order( symbol=selected_symbol, side=Client.SIDE_SELL, type=Client.ORDER_TYPE_MARKET, leverage=20, quantity=qty ) # 弹出订单成功提示 pop = Toplevel(root) pop.title("SELL 订单成功") pop.geometry("250x150") pop.config(bg="#00ff00") pop_label = Label(pop, text=f"订单已提交\n订单ID: {order['orderId']}", bg="#000000", fg="#ffffff", font=("Arial", 10)) pop_label.pack(pady=20) except Exception as e: messagebox.showerror("下单失败", str(e)) b = Button(root, text="卖空(Sell)", bg="#ff4444", fg="white", command=buttonFunction, width=10) b.config(font=("Arial", 12)) b.pack(side=LEFT, padx=20, pady=20) # 买单按钮逻辑 def buttonFunction2(): global latest_price selected_symbol = combo_box.get() input_amount_str = qty_entry.get() # 输入验证 if not selected_symbol: messagebox.showerror("错误", "请先选择交易对") return if not input_amount_str.replace('.', '', 1).isdigit(): messagebox.showerror("错误", "请输入有效的数字金额") return if latest_price <= 0: messagebox.showerror("错误", "未获取到有效价格,请检查交易对选择") return input_amount = float(input_amount_str) # 计算实际下单量 raw_qty = input_amount / latest_price # 获取币安要求的数量步长并调整精度 step_size = get_quantity_step(selected_symbol) qty = round(raw_qty / step_size) * step_size try: order = client.futures_create_order( symbol=selected_symbol, side=Client.SIDE_BUY, type=Client.ORDER_TYPE_MARKET, leverage=20, quantity=qty ) # 弹出订单成功提示 pop = Toplevel(root) pop.title("BUY 订单成功") pop.geometry("250x150") pop.config(bg="#00ff00") pop_label = Label(pop, text=f"订单已提交\n订单ID: {order['orderId']}", bg="#000000", fg="#ffffff", font=("Arial", 10)) pop_label.pack(pady=20) except Exception as e: messagebox.showerror("下单失败", str(e)) b2 = Button(root, text="做多(Buy)", bg="#00cc00", fg="white", command=buttonFunction2, width=10) b2.config(font=("Arial", 12)) b2.pack(side=RIGHT, padx=20, pady=20) root.mainloop()
关键修复点说明
价格获取逻辑优化
- 新增全局变量
latest_price存储最新价格,用于后续下单计算 - 仅当选中交易对时才发起API请求,避免无意义的错误调用
- 移除无效的
timeframe参数,符合Binance期货API规范 - 添加错误捕获,显示价格获取失败原因
- 新增全局变量
下单量计算实现
- 实现
实际下单量=输入金额/最新价格的核心公式 - 新增
get_quantity_step函数获取币安要求的数量步长,确保下单量符合平台规则 - 对计算结果按步长取整,避免因精度问题导致下单失败
- 实现
输入验证与错误处理
- 检查交易对是否选中、输入金额是否为有效数字、价格是否有效
- 对API调用异常进行捕获,弹出明确的错误提示
- 订单成功后显示订单ID,提升用户体验
界面与性能优化
- 调整界面布局,增加间距提升可读性
- 将价格更新频率改为1秒一次,避免API请求过于频繁触发限流
内容的提问来源于stack exchange,提问作者Eq1NoX
相关产品推荐
相关产品推荐

