Programming Project Part #3
Today we're going to build the GUI for this bot.
Here’s how the Tkinter GUI is made and what it looks like, plus a quick recap of how the bot works.
The idea is to have the first window ask for the Binance API keys and Telegram tokens. Once we hit "Save," the GUI will verify the Binance credentials. If they're valid, it will create and save a config file for the bot to read in the future.
Once that’s done, we can select the coin we want to track, the target amount to maintain, the min notional (meaning the minimum amount allowed to buy/sell), and the % of profit we want to make on each buy.
So for example:
If we have a target of $100 in BTC and the price drops, we still own the same amount of BTC, but the dollar value we hold is now less—say $99. The bot should then buy $1 worth of BTC to bring us back up to target.
Now, if we set our profit % to 20%, it will only sell once that $1 buy reaches $1.20—ensuring a profit.
There are two main scenarios:
If the price consistently drops
If the price consistently rises
1: If the price drops consistently
Example: We own $100 in BTC and set a budget of $50. If the price of BTC drops and our holding is now worth $99, we use $1 from our budget to buy more. We now hold slightly more BTC (still worth around $100), and our budget is $49.
This continues until the budget is spent. The idea is that every time the price drops, we track the buys.
The bot can run as often as you want—say, every 10 seconds. If the balance drops by $1 in that window, it buys. If it's checking every 10 minutes instead, the price might have dropped more, and we’d buy a bigger chunk.
2: If the price rises consistently
In this case, I decided the bot should sell as much as it wants above the target. So if we have $100 in BTC and it grows to $110, the bot just sells the extra $10.
However, if we have a pending profit-sell (a buy we made earlier that hasn't reached its profit target yet), we don’t want to include that amount in the sell. So really, we’re tracking two things:
The difference between the current value and the target, and
Any open buy positions still waiting to hit their profit %
Here's a quick look at the files it creates and how they’re structured:
Honestly, I don’t know if this is going to turn into a good trading bot. I know Binance already has something similar on their site, but I started this project before I knew that—and I want to finish it just to have something of my own that (hopefully) makes a profit.
Side note: it’s kind of nice to understand how it all works and have it running locally. Even though it’s still using Binance’s APIs, it just feels safer.
heres the code of the bot incase someone wants to copy and paste it :
import tkinter as tk
from tkinter import messagebox, ttk
import json, os
from binance.client import Client
CREDENTIALS_PATH = "credentials.json"
COINS_PATH = "coins.json"
class RebalancerGUI:
def __init__(self, root):
self.root = root
self.root.title("Simple Rebalancing Bot Setup")
self.api_key = tk.StringVar()
self.api_secret = tk.StringVar()
self.telegram_token = tk.StringVar()
self.telegram_chat_id = tk.StringVar()
self.symbol_var = tk.StringVar()
self.target_var = tk.StringVar()
self.budget_var = tk.StringVar()
self.min_notional_var = tk.StringVar()
self.profit_var = tk.StringVar()
self.client = None
self.pairs = []
self.show_credentials_screen()
def show_credentials_screen(self):
self.clear_root()
tk.Label(self.root, text="Binance API Key").pack()
tk.Entry(self.root, textvariable=self.api_key).pack()
tk.Label(self.root, text="Binance API Secret").pack()
tk.Entry(self.root, textvariable=self.api_secret, show="*").pack()
tk.Label(self.root, text="Telegram Bot Token (optional)").pack()
tk.Entry(self.root, textvariable=self.telegram_token).pack()
tk.Label(self.root, text="Telegram Chat ID (optional)").pack()
tk.Entry(self.root, textvariable=self.telegram_chat_id).pack()
tk.Button(self.root, text="Save and Continue", command=self.verify_credentials).pack(pady=10)
def verify_credentials(self):
try:
self.client = Client(self.api_key.get(), self.api_secret.get())
self.client.get_account() # test credentials
creds = {
"binance_api": self.api_key.get(),
"binance_secret": self.api_secret.get(),
"telegram_token": self.telegram_token.get(),
"telegram_chat_id": self.telegram_chat_id.get()
}
with open(CREDENTIALS_PATH, "w") as f:
json.dump(creds, f, indent=2)
self.fetch_usdt_pairs()
self.show_config_screen()
except Exception as e:
messagebox.showerror("Error", f"Invalid Binance credentials:\n{e}")
def fetch_usdt_pairs(self):
info = self.client.get_exchange_info()
self.pairs = sorted([s['symbol'] for s in info['symbols'] if s['symbol'].endswith("USDT") and s['status'] == 'TRADING'])
def show_config_screen(self):
self.clear_root()
tk.Label(self.root, text="Select USDT Pair").pack()
dropdown = ttk.Combobox(self.root, textvariable=self.symbol_var, values=self.pairs)
dropdown.pack()
tk.Label(self.root, text="Target Value (USDT)").pack()
tk.Entry(self.root, textvariable=self.target_var).pack()
tk.Label(self.root, text="Dip Budget (USDT)").pack()
tk.Entry(self.root, textvariable=self.budget_var).pack()
tk.Label(self.root, text="Min Notional (manual)").pack()
tk.Entry(self.root, textvariable=self.min_notional_var).pack()
tk.Label(self.root, text="Profit %").pack()
tk.Entry(self.root, textvariable=self.profit_var).pack()
tk.Button(self.root, text="Save Coin Config", command=self.save_coin_config).pack(pady=10)
def save_coin_config(self):
try:
data = {
"symbol": self.symbol_var.get(),
"target": float(self.target_var.get()),
"budget": float(self.budget_var.get()),
"min_notional": float(self.min_notional_var.get()),
"profit_pct": float(self.profit_var.get())
}
with open(COINS_PATH, "w") as f:
json.dump([data], f, indent=2)
messagebox.showinfo("Saved", "Coin config saved to coins.json")
except ValueError:
messagebox.showerror("Error", "Please enter valid numbers")
def clear_root(self):
for widget in self.root.winfo_children():
widget.destroy()if __name__ == "__main__":
root = tk.Tk()
app = RebalancerGUI(root)
root.mainloop()