def __init__(self, app, parent, delay = 1000, stub=False, price_x=None, price_y=None, bought_x=None, bought_y=None, sold_x=None, sold_y=None, x_lowest_sell_order=None, y_lowest_sell_order=None, x_highest_buy_order=None, y_highest_buy_order=None ): tk.Frame.__init__(self, parent, bg="black") self.app = app self.parent = parent self.stub = stub self.delay = delay self.x_axis_window_size = 51 # todo: button for changing this self.coin_balance = tk.StringVar() self.base_balance = tk.StringVar() self.base_vol = tk.StringVar() self.quote_vol = tk.StringVar() self.base_vol_profit = tk.StringVar() self.quote_vol_profit = tk.StringVar() self.coin_balance.set("0") self.base_balance.set("0") self.base_vol.set("0") self.quote_vol.set("0") self.base_vol_profit.set("0") self.quote_vol_profit.set("0") self.orderbook = None #self.label = tk.Label(self, text=self.parent.pair, font=LARGE_FONT) self.label = ttk.Label(self, text=self.parent.name, style="app.TLabel") self.fig, self.ax = plt.subplots(1, 2, sharey=True, tight_layout=True, gridspec_kw = {'width_ratios':[4, 1]}) self.x_price = price_x if price_x else [] self.y_price = price_y if price_y else [] self.line_price = Line2D(self.x_price, self.y_price, color="blue") self.ax[0].add_line(self.line_price) self.x_bought = bought_x if bought_x else [] self.y_bought = bought_y if bought_y else [] self.boughtScatter = self.ax[0].scatter(self.x_bought, self.y_bought, color="lime", marker="P", s=100) self.x_sold = sold_x if sold_x else [] self.y_sold = sold_y if sold_y else [] self.scatter_sold = self.ax[0].scatter(self.x_sold, self.y_sold, color="salmon", marker="D", s=100) self.x_lowest_sell_order = x_lowest_sell_order if x_lowest_sell_order else [] self.y_lowest_sell_order = y_lowest_sell_order if y_lowest_sell_order else [] self.line_lowest_sell_order = Line2D(self.x_lowest_sell_order, self.y_lowest_sell_order, color="red") self.ax[0].add_line(self.line_lowest_sell_order) self.x_highest_buy_order = x_highest_buy_order if x_highest_buy_order else [] self.y_highest_buy_order = y_highest_buy_order if y_highest_buy_order else [] self.line_highest_buy_order = Line2D(self.x_highest_buy_order, self.y_highest_buy_order, color="green") self.ax[0].add_line(self.line_highest_buy_order) #plt.tight_layout() #self.fig = Figure(figsize=(5, 5), dpi=100) #self.graph = self.fig.add_subplot(111) # ----------------------------- self.ax_depth = self.ax[1] self.ax_depth.grid(color='gray', linestyle='--', linewidth=.5) # --------------------------- self.canvas = FigureCanvasTkAgg(self.fig, self) self.ax[0].grid(color='gray', linestyle='--', linewidth=.5) self.ax[0].set_title(self.parent.name, fontsize=10) self.canvas.draw() self.fig.canvas.mpl_connect('scroll_event', self.process_scroll) #self.draw_graph() self.toolbar_frame = tk.Frame(self) self.toolbar = NavigationToolbar2TkAgg(self.canvas, self.toolbar_frame,) self.toolbar.update() # -------------------------------------- self.options_frame = tk.Frame(self,bg = "black") self.x_axis_auto_scroll = MyWidget(self.app, self.options_frame, optional=True, handle="auto_scroll") self.x_axis_window_size_input = MyWidget(self.app, self.options_frame, choices="entry",ewidth=4, handle="width", startVal="100") self.x_axis_auto_scroll.grid(row=0, column=0, sticky=tk.NW, padx=(5.0), pady=(5,0)) self.x_axis_window_size_input.grid(row=1, column=0, sticky=tk.NW, padx=(28.0), pady=(2,10)) # -------------------------------------- self.stats_frame = ttk.Frame(self.options_frame, style="app.TFrame") self.profit_base = ttk.Label(self.stats_frame, text="%s \u0394bal:" % self.parent.base_title[:4], style="app.TLabel") self.profit_base2 = ttk.Label(self.stats_frame, textvariable=self.base_balance, style="app.TLabel") self.profit_alt = ttk.Label(self.stats_frame, text="%s \u0394bal:" % self.parent.coin_title[:4], style="app.TLabel") self.profit_alt2 = ttk.Label(self.stats_frame, textvariable=self.coin_balance, style="app.TLabel") self.base_vol_lab = ttk.Label(self.stats_frame, text="BVol:", style="app.TLabel") self.base_vol_lab2 = ttk.Label(self.stats_frame, textvariable=self.base_vol, style="app.TLabel") self.quote_vol_lab = ttk.Label(self.stats_frame, text="QVol:", style="app.TLabel") self.quote_vol_lab2 = ttk.Label(self.stats_frame, textvariable=self.quote_vol, style="app.TLabel") self.base_vol_profit_lab = ttk.Label(self.stats_frame, text="BProfit:", style="app.TLabel") self.base_vol_profit_lab2 = ttk.Label(self.stats_frame, textvariable=self.base_vol_profit, style="app.TLabel") self.quote_vol_profit_lab = ttk.Label(self.stats_frame, text="QProfit:", style="app.TLabel") self.quote_vol_profit_lab2 = ttk.Label(self.stats_frame, textvariable=self.quote_vol_profit, style="app.TLabel") self.profit_base.grid(row=1, column=0, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.profit_base2.grid(row=1, column=1, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.profit_alt.grid(row=0, column=0, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.profit_alt2.grid(row=0, column=1, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.base_vol_lab.grid(row=1, column=2, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.base_vol_lab2.grid(row=1, column=3, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.quote_vol_lab.grid(row=0, column=2, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.quote_vol_lab2.grid(row=0, column=3, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.base_vol_profit_lab.grid(row=1, column=4, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.base_vol_profit_lab2.grid(row=1, column=5, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.quote_vol_profit_lab.grid(row=0, column=4, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.quote_vol_profit_lab2.grid(row=0, column=5, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.stats_frame.grid(row=0, column=2, rowspan=2, sticky=tk.NW, padx=(28.0), pady=(2,10)) # -------------------------------------- self.toolbar_frame.pack(side=tk.TOP, anchor=tk.W, pady=(4,10)) #self.label.pack(pady=(20,0), padx=10, side=tk.TOP) self.canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True) self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True) self.options_frame.pack(side=tk.TOP, anchor=tk.W, fill=tk.BOTH, expand=False) # -------------------------------------- self.x_low, self.x_hi = self.ax[0].get_xlim() self.y_low, self.y_hi = self.ax[0].get_ylim() #self.loop = animation.FuncAnimation(f, self.refresh,fargs = , interval=1000) self.fake_prev_order = "sell" if self.stub: self.fake_spread = 4 x_this = datetime.datetime.now() #self.fake_orders = {"buy": [(244, 0.5, x_this), (241, 0.5, x_this),(236, 0.5, x_this),(231, 0.5, x_this),(226, 0.5, x_this),(221, 0.5, x_this),(216, 0.5, x_this)], # "sell": [(253, 0.5, x_this),(258, 0.5, x_this), (263, 0.5, x_this), (263, 0.5, x_this), (268, 0.5, x_this), (273, 0.5, x_this), (278, 0.5, x_this)]} self.fake_orders = [dict(price=this_price, date=x_this, type="buy", amount=0.5) for this_price in range(244,100,-10)] self.fake_orders.extend([dict(price=this_price, date=x_this, type="sell", amount=0.5) for this_price in range(253,400,10)])
def __init__(self, app, parent, owner, persist=None, stub=False, auto_start=False, starting_stats=None, *args, **kwargs): ttk.Frame.__init__(self, parent, style="app.TFrame", *args, **kwargs) self.app = app # root self.parent = parent # containing frame self.owner = owner self.stub = stub self.is_active = False self.title_var = tk.StringVar() self.coin_title = "coin" self.base_title = "base" self.exchange_title = "<exchange>" if self.stub: self.name = "XMR/BTC Stub" else: self.name = "New Merkato" self.title_var.set(str(self.name)) # merkato args #self.auth_frame = ttk.Frame(self, style="app.TFrame") self.bot = None if persist: self.name = persist["coin"] + "/" + persist[ "base"] + " " + persist["configuration"]["exchange"] self.title_var.set(str(self.name)) self.bot = Merkato(**persist) #presumably from db # -------------------- self.exchange_frame = ttk.Frame(self, style="app.TFrame") self.exchange_menu, self.exchange_index = database_utils.get_all_exchanges( ) self.exchange_name = MyWidget(self.app, self.exchange_frame, handle="exchange", startVal="test", choices=self.exchange_menu) self.coin = MyWidget(self.app, self.exchange_frame, handle="coin", startVal="XMR", choices=["XMR", "LTC", "ETH", "DOGE", "PEPECASH"]) self.base = MyWidget(self.app, self.exchange_frame, handle="base", startVal="BTC", choices=["BTC", "USDT"]) #self.public_key = MyWidget(self.app, self.exchange_frame, handle="pub. key", choices="entry") #self.private_key = MyWidget(self.app, self.exchange_frame, handle="priv. key", is_password=True, choices="entry") self.ask_budget = MyWidget(self.app, self.exchange_frame, handle="coin reserve", startVal=636, choices="entry") self.bid_budget = MyWidget(self.app, self.exchange_frame, handle="base reserve", startVal=10, choices="entry") self.spread = MyWidget(self.app, self.exchange_frame, handle="spread [%]", startVal=5.0, choices="entry") self.margin = MyWidget(self.app, self.exchange_frame, handle="profit margin [%]", startVal="0", choices=[str(i) for i in range(101)]) self.execute = ttk.Button(self.exchange_frame, text="Launch", cursor="shuttle", command=self.start) self.exchange_name.grid(row=0, column=0, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.coin.grid(row=1, column=0, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.base.grid(row=2, column=0, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) #self.public_key.grid(row=3, column=0, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) #self.private_key.grid(row=4, column=0, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.ask_budget.grid(row=5, column=0, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.bid_budget.grid(row=6, column=0, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.spread.grid(row=7, column=0, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.margin.grid(row=8, column=0, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.execute.grid(row=9, column=0, sticky=tk.NE, padx=(10, 5), pady=(15, 5)) # -------------------- self.util_frame = ttk.Frame(self, style="app.TFrame") self.kill_button = ttk.Button(self.util_frame, text="Kill", cursor="shuttle", command=self.kill) self.kill_button.grid(row=0, column=0, sticky=tk.SE, padx=(10, 5), pady=(15, 5)) self.add_assets_type = MyWidget( self.app, self.util_frame, handle="Add Asset", startVal="XMR", choices=["XMR", "BTC", "ETH", "DOGE", "PEPECASH"]) self.add_assets_type.grid(row=1, column=0, sticky=tk.SE, padx=(10, 5), pady=(15)) self.add_assets_amount = MyWidget(self.app, self.util_frame, handle="amount to add", startVal=1.0, choices="entry") self.add_assets_amount.grid(row=2, column=0, sticky=tk.SE, padx=(10, 5), pady=(15)) self.add_assets_button = ttk.Button(self.util_frame, text="Add Assets", cursor="shuttle", command=self.add_assets) self.add_assets_button.grid(row=3, column=0, sticky=tk.SE, padx=(10, 5), pady=(15)) # -------------------- if not starting_stats: starting_stats = {"price_x": []} self.graph = Graph(self.app, self, stub=self.stub, **starting_stats) self.graph.grid(row=0, column=0, rowspan=3, padx=(5, 10)) #self.auth_frame.grid(row = 0, column=1, sticky=tk.NE, padx=(10,10), pady=(20,5)) if not self.bot: self.exchange_frame.grid(row=0, column=1, sticky=tk.NE, padx=(10, 10), pady=(20, 5)) self.util_frame.grid(row=1, column=1, sticky=tk.SE, padx=(10, 10), pady=(10, 5))
class Graph(tk.Frame): def __init__(self, app, parent, delay = 1000, stub=False, price_x=None, price_y=None, bought_x=None, bought_y=None, sold_x=None, sold_y=None, x_lowest_sell_order=None, y_lowest_sell_order=None, x_highest_buy_order=None, y_highest_buy_order=None ): tk.Frame.__init__(self, parent, bg="black") self.app = app self.parent = parent self.stub = stub self.delay = delay self.x_axis_window_size = 51 # todo: button for changing this self.coin_balance = tk.StringVar() self.base_balance = tk.StringVar() self.base_vol = tk.StringVar() self.quote_vol = tk.StringVar() self.base_vol_profit = tk.StringVar() self.quote_vol_profit = tk.StringVar() self.coin_balance.set("0") self.base_balance.set("0") self.base_vol.set("0") self.quote_vol.set("0") self.base_vol_profit.set("0") self.quote_vol_profit.set("0") self.orderbook = None #self.label = tk.Label(self, text=self.parent.pair, font=LARGE_FONT) self.label = ttk.Label(self, text=self.parent.name, style="app.TLabel") self.fig, self.ax = plt.subplots(1, 2, sharey=True, tight_layout=True, gridspec_kw = {'width_ratios':[4, 1]}) self.x_price = price_x if price_x else [] self.y_price = price_y if price_y else [] self.line_price = Line2D(self.x_price, self.y_price, color="blue") self.ax[0].add_line(self.line_price) self.x_bought = bought_x if bought_x else [] self.y_bought = bought_y if bought_y else [] self.boughtScatter = self.ax[0].scatter(self.x_bought, self.y_bought, color="lime", marker="P", s=100) self.x_sold = sold_x if sold_x else [] self.y_sold = sold_y if sold_y else [] self.scatter_sold = self.ax[0].scatter(self.x_sold, self.y_sold, color="salmon", marker="D", s=100) self.x_lowest_sell_order = x_lowest_sell_order if x_lowest_sell_order else [] self.y_lowest_sell_order = y_lowest_sell_order if y_lowest_sell_order else [] self.line_lowest_sell_order = Line2D(self.x_lowest_sell_order, self.y_lowest_sell_order, color="red") self.ax[0].add_line(self.line_lowest_sell_order) self.x_highest_buy_order = x_highest_buy_order if x_highest_buy_order else [] self.y_highest_buy_order = y_highest_buy_order if y_highest_buy_order else [] self.line_highest_buy_order = Line2D(self.x_highest_buy_order, self.y_highest_buy_order, color="green") self.ax[0].add_line(self.line_highest_buy_order) #plt.tight_layout() #self.fig = Figure(figsize=(5, 5), dpi=100) #self.graph = self.fig.add_subplot(111) # ----------------------------- self.ax_depth = self.ax[1] self.ax_depth.grid(color='gray', linestyle='--', linewidth=.5) # --------------------------- self.canvas = FigureCanvasTkAgg(self.fig, self) self.ax[0].grid(color='gray', linestyle='--', linewidth=.5) self.ax[0].set_title(self.parent.name, fontsize=10) self.canvas.draw() self.fig.canvas.mpl_connect('scroll_event', self.process_scroll) #self.draw_graph() self.toolbar_frame = tk.Frame(self) self.toolbar = NavigationToolbar2TkAgg(self.canvas, self.toolbar_frame,) self.toolbar.update() # -------------------------------------- self.options_frame = tk.Frame(self,bg = "black") self.x_axis_auto_scroll = MyWidget(self.app, self.options_frame, optional=True, handle="auto_scroll") self.x_axis_window_size_input = MyWidget(self.app, self.options_frame, choices="entry",ewidth=4, handle="width", startVal="100") self.x_axis_auto_scroll.grid(row=0, column=0, sticky=tk.NW, padx=(5.0), pady=(5,0)) self.x_axis_window_size_input.grid(row=1, column=0, sticky=tk.NW, padx=(28.0), pady=(2,10)) # -------------------------------------- self.stats_frame = ttk.Frame(self.options_frame, style="app.TFrame") self.profit_base = ttk.Label(self.stats_frame, text="%s \u0394bal:" % self.parent.base_title[:4], style="app.TLabel") self.profit_base2 = ttk.Label(self.stats_frame, textvariable=self.base_balance, style="app.TLabel") self.profit_alt = ttk.Label(self.stats_frame, text="%s \u0394bal:" % self.parent.coin_title[:4], style="app.TLabel") self.profit_alt2 = ttk.Label(self.stats_frame, textvariable=self.coin_balance, style="app.TLabel") self.base_vol_lab = ttk.Label(self.stats_frame, text="BVol:", style="app.TLabel") self.base_vol_lab2 = ttk.Label(self.stats_frame, textvariable=self.base_vol, style="app.TLabel") self.quote_vol_lab = ttk.Label(self.stats_frame, text="QVol:", style="app.TLabel") self.quote_vol_lab2 = ttk.Label(self.stats_frame, textvariable=self.quote_vol, style="app.TLabel") self.base_vol_profit_lab = ttk.Label(self.stats_frame, text="BProfit:", style="app.TLabel") self.base_vol_profit_lab2 = ttk.Label(self.stats_frame, textvariable=self.base_vol_profit, style="app.TLabel") self.quote_vol_profit_lab = ttk.Label(self.stats_frame, text="QProfit:", style="app.TLabel") self.quote_vol_profit_lab2 = ttk.Label(self.stats_frame, textvariable=self.quote_vol_profit, style="app.TLabel") self.profit_base.grid(row=1, column=0, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.profit_base2.grid(row=1, column=1, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.profit_alt.grid(row=0, column=0, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.profit_alt2.grid(row=0, column=1, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.base_vol_lab.grid(row=1, column=2, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.base_vol_lab2.grid(row=1, column=3, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.quote_vol_lab.grid(row=0, column=2, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.quote_vol_lab2.grid(row=0, column=3, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.base_vol_profit_lab.grid(row=1, column=4, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.base_vol_profit_lab2.grid(row=1, column=5, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.quote_vol_profit_lab.grid(row=0, column=4, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.quote_vol_profit_lab2.grid(row=0, column=5, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.stats_frame.grid(row=0, column=2, rowspan=2, sticky=tk.NW, padx=(28.0), pady=(2,10)) # -------------------------------------- self.toolbar_frame.pack(side=tk.TOP, anchor=tk.W, pady=(4,10)) #self.label.pack(pady=(20,0), padx=10, side=tk.TOP) self.canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True) self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True) self.options_frame.pack(side=tk.TOP, anchor=tk.W, fill=tk.BOTH, expand=False) # -------------------------------------- self.x_low, self.x_hi = self.ax[0].get_xlim() self.y_low, self.y_hi = self.ax[0].get_ylim() #self.loop = animation.FuncAnimation(f, self.refresh,fargs = , interval=1000) self.fake_prev_order = "sell" if self.stub: self.fake_spread = 4 x_this = datetime.datetime.now() #self.fake_orders = {"buy": [(244, 0.5, x_this), (241, 0.5, x_this),(236, 0.5, x_this),(231, 0.5, x_this),(226, 0.5, x_this),(221, 0.5, x_this),(216, 0.5, x_this)], # "sell": [(253, 0.5, x_this),(258, 0.5, x_this), (263, 0.5, x_this), (263, 0.5, x_this), (268, 0.5, x_this), (273, 0.5, x_this), (278, 0.5, x_this)]} self.fake_orders = [dict(price=this_price, date=x_this, type="buy", amount=0.5) for this_price in range(244,100,-10)] self.fake_orders.extend([dict(price=this_price, date=x_this, type="sell", amount=0.5) for this_price in range(253,400,10)]) #self._root().after(5000, self.refresh, self.fake_data()) def process_scroll(self, event): pass def draw_orderbook(self, orderbook=None): if orderbook: bid_prices = [float(order[0]) for order in orderbook["bids"]] bid_amounts = [float(order[1]) for order in orderbook["bids"]] ask_prices = [float(order[0]) for order in orderbook["asks"]] ask_amounts = [float(order[1]) for order in orderbook["asks"]] num_bins_bids = 100 # max(100, len(set(orderbook["bids"]))) num_bins_asks = 100 # max(100, len(set(orderbook["asks"]))) self.ax_depth.clear() #self.ax_depth.autoscale(False) self.ax_depth.grid(color='gray', linestyle='--', linewidth=.5) self.ax_depth.hist(bid_prices, weights=bid_amounts, bins=num_bins_bids, orientation="horizontal", color="g") self.ax_depth.hist(ask_prices, weights=ask_amounts, bins=num_bins_asks, orientation="horizontal", color="r") #self.ax_depth.autoscale(axis="x") #self.ax_depth.autoscale(False) def draw_depth(self, bps=.35): if self.orderbook: bidasks = self.orderbook.copy() best_bid = max([float(price) for price, amount, *rest in bidasks["bids"]]) best_ask = min([float(price) for price, amount, *rest in bidasks["asks"]]) worst_bid = best_bid * (1 - bps) worst_ask = best_ask * (1 + bps) filtered_bids = sorted( [(float(bid[0]), float(bid[1])) for bid in bidasks["bids"] if float(bid[0]) >= worst_bid], key=lambda x: -x[0]) filtered_asks = sorted( [(float(ask[0]), float(ask[1])) for ask in bidasks["asks"] if float(ask[0]) <= worst_ask], key=lambda x: +x[0]) bsizeacc = 0 bhys = [] # bid - horizontal - ys bhxmins = [] # bid - horizontal - xmins bhxmaxs = [] # ... bvxs = [] bvymins = [] bvymaxs = [] asizeacc = 0 ahys = [] ahxmins = [] ahxmaxs = [] avxs = [] avymins = [] avymaxs = [] for (p1, s1), (p2, s2) in zip(filtered_bids, filtered_bids[1:]): bvymins.append(bsizeacc) if bsizeacc == 0: bsizeacc += s1 bhys.append(bsizeacc) bhxmins.append(p2) bhxmaxs.append(p1) bvxs.append(p2) bsizeacc += s2 bvymaxs.append(bsizeacc) for (p1, s1), (p2, s2) in zip(filtered_asks, filtered_asks[1:]): avymins.append(asizeacc) if asizeacc == 0: asizeacc += s1 ahys.append(asizeacc) ahxmins.append(p1) ahxmaxs.append(p2) avxs.append(p2) asizeacc += s2 avymaxs.append(asizeacc) self.ax_depth.clear() self.ax_depth.grid(color='gray', linestyle='--', linewidth=.5) self.ax_depth.vlines(bhys[:], bhxmins[:], bhxmaxs[:], color="green") self.ax_depth.hlines(bvxs, bvymins, bvymaxs, color="green") self.ax_depth.vlines(ahys[:], ahxmins[:], ahxmaxs[:], color="red") self.ax_depth.hlines(avxs, avymins, avymaxs, color="red") def calc_stats(self): ''' TODO Function Description ''' # self.coin_balance.set(str(float(self.coin_balance.get()) + order[1])) base_cumulative = float(self.base_balance.get()) coin_cumulative = float(self.coin_balance.get()) selling_scenario = coin_cumulative < 0 and base_cumulative > 0 buying_scenario = coin_cumulative > 0 and base_cumulative < 0 zero_scenario = coin_cumulative == 0 and base_cumulative == 0 free_money_scenario = (coin_cumulative >= 0 and base_cumulative > 0) or (coin_cumulative > 0 and base_cumulative >= 0) def fake_data(self): print("------------- faking data ------------") x_this = datetime.datetime.now() old_price = self.y_price[-1] price = abs(old_price + random.randint(-5, 5)) print(x_this, price) print("fake orders", repr(self.fake_orders)) data = { "price": (x_this, price), "open_orders": list(self.fake_orders) } # ---------- print("------------- fake: filling orders ------------") closed = {"filled_orders": []} this_fake_orders = list(self.fake_orders) fdt = datetime.timedelta(seconds=3) for order in this_fake_orders: if order["type"] == "buy": if price <= float(order["price"]): closed["filled_orders"].append(dict(amount=float(order["amount"]), price=float(order["price"]), date=x_this - fdt, type="buy")) # was (order[0], order[1], x_this - .5)) self.fake_orders.append(dict(amount=float(order["amount"]), price=float(order["price"]) + self.fake_spread, date=x_this - fdt, type="sell")) # was ((order[0] + self.fake_spread, order[1], x_this - .5)) self.fake_orders.remove(order) if order["type"] == "sell": if price >= float(order["price"]): closed["filled_orders"].append(dict(amount=float(order["amount"]), price=float(order["price"]), date=x_this - fdt, type="sell")) # was (order[0], order[1], x_this - .5)) self.fake_orders.append(dict(amount=float(order["amount"]), price=float(order["price"]) - self.fake_spread, date=x_this - fdt, type="buy")) # was ((order[0] + self.fake_spread, order[1], x_this - .5)) self.fake_orders.remove(order) # ----------- # print(old_price, price,trigger_buy,trigger_sell) # if trigger_buy or trigger_sell: # print("#------------\nORDER ALERT:") # closed = {"filled_orders":{"buy":[], # "sell":[]}} # if trigger_sell: # self.fake_prev_order = "sell" # closed["filled_orders"]["sell"].append((258, 0.5, x_this-1)) # if trigger_buy: # self.fake_prev_order = "buy" # closed["filled_orders"]["buy"].append((241, 0.5, x_this-1)) # print(data) # data.update(closed) if closed["filled_orders"]: print("#------------\nORDER ALERT:") data.update(closed) order_book = {"asks": [], "bids": []} for step in range(2,50): ask_price = price * (1 + float(step) / 300.0) ask_amount = max(0, random.randint(-3, 5)) bid_price = price * (1 - float(step) / 300.0) bid_amount = max(0, random.randint(-3, 5)) order_book["asks"].append([str(ask_price), str(ask_amount)]) order_book["bids"].append([str(bid_price), str(bid_amount)]) data["orderbook"] = order_book print(repr(data)) return data def date_as_object(self, date): ''' TODO Function Description ''' # TODO: do something with date if isinstance(date,datetime.date): #print("already a datetime object") return date date_object = datetime.datetime.strptime(date, "%Y-%m-%d %H:%M:%S") return date_object def ingest_data(self, data): print("------------- ingesting data ------------") """ for k,v in data.items(): if not k =="filled_orders": pprint(k) pprint(v) else: pprint(k) if v: pprint(v[0]) """ self.base_vol.set(str(float(data['base_volume']))) self.quote_vol.set(str(float(data['quote_volume']))) unmade_orders = get_unmade_orders(data['price'][1], data['starting_price'], data['starting_base'], data['starting_quote'], data['spread'], data['step']) base_vol_profit = str((float(data['base_volume']) - unmade_orders['base']) * data['spread']) quote_vol_profit = str((float(data['quote_volume']) - unmade_orders['quote']) * data['spread'] ) self.base_vol_profit.set(str(float(base_vol_profit))) self.quote_vol_profit.set(str(float(quote_vol_profit))) # BROKEN CODE FOR CALCUATING PROFIT WITH DOUG's OLD METHOD # if len(self.y_price) > 0: # market_price = float(self.y_price[-1]) # starting_price = data['starting_price'] # start_base = data['bid_reserved_balance'] * 4 # start_quote = data['ask_reserved_balance'] * 4 # print("data['ask_reserved_balance']", data['ask_reserved_balance'], "data['bid_reserved_balance']", data['bid_reserved_balance']) # spread = data['spread'] # expected_balances = get_expected_balances(market_price, starting_price, start_base, start_quote, spread, 1.0033 ) # print('expected_balance', expected_balances) # orderbook_balances = get_orderbook_balances(data['open_orders']) # print('orderbook_balances', orderbook_balances) # base_profit = data['bid_reserved_balance'] + orderbook_balances[0] - expected_balances[0] # quote_profit = data['ask_reserved_balance'] + orderbook_balances[1] - expected_balances[1] # self.coin_balance.set(str(float(quote_profit))) # self.base_balance.set(str(float(base_profit))) if "price" in data: px, py = data["price"] py = float(py) self.x_price.append(self.date_as_object(px)) self.y_price.append(py) # ----------------------------------------------------- if "filled_orders" in data: ''' Format: [ {'id': '430236', 'date': '2018-05-30 17:03:41', 'type': 'buy', 'price': '0.00000290', 'amount': '78275.86206896', 'total': '0.22700000', 'fee': '0.00000000', 'feepercent': '0.000', 'orderId': '86963799', 'market': 'BTC', 'coin': 'PEPECASH', 'market_pair': 'BTC_PEPECASH'}, {'id': '423240', 'date': '2018-04-22 06:19:19', 'type': 'sell', 'price': '0.00000500', 'amount': '6711.95200000', 'total': '0.03355976', 'fee': '0.00000000', 'feepercent': '0.000', 'orderId': '90404882', 'market': 'BTC', 'coin': 'PEPECASH', 'market_pair': 'BTC_PEPECASH'}, ... ] ''' for filled in data["filled_orders"]: if "buy" == filled["type"]: self.coin_balance.set(str(float(self.coin_balance.get()) + float(filled["amount"]))) self.base_balance.set(str(float(self.base_balance.get()) - (float(filled["amount"]) * float(filled["price"])))) bx = self.date_as_object(filled["date"]) # date by = float(filled["price"]) self.x_bought.append(bx) self.y_bought.append(by) elif "sell" == filled["type"]: self.coin_balance.set(str(float(self.coin_balance.get()) - float(filled["amount"]))) self.base_balance.set(str(float(self.base_balance.get()) + (float(filled["amount"]) * float(filled["price"])))) sx = self.date_as_object(filled["date"]) # date sy = float(filled["price"]) self.x_sold.append(sx) self.y_sold.append(sy) # ----------------------------------------------------- order_price_index = 0 # sort on first element of tuple which should be price (for now) order_time_index = 2 if "open_orders" in data: if isinstance(data["open_orders"], dict): data["open_orders"] = [v for k,v in data["open_orders"].items()] ''' {'coin': 'PEPECASH', 'market': 'BTC', 'date': '2017-10-14 09:05:27', 'type': 'sell', 'price': '0.00000835', 'amount': '5988.02395209', 'total': '0.04999999', 'id': '85911467', 'filledamount': '0.00000000', 'initamount': '5988.02395209', 'market_pair': 'BTC_PEPECASH'}, '85902008': {'coin': 'PEPECASH', 'market': 'BTC', 'date': '2017-10-13 18:42:02', 'type': 'buy', 'price': '0.00000227', 'amount': '70484.58149780', 'total': '0.16000000', 'id': '85902008', 'filledamount': '0.00000000', 'initamount': '70484.58149780', 'market_pair': 'BTC_PEPECASH'} ''' sell_amounts = [float(order["price"]) for order in data["open_orders"] if order["type"] == "sell"] buy_amounts = [float(order["price"]) for order in data["open_orders"] if order["type"] == "buy"] if sell_amounts: lowest_sell = min(sell_amounts) self.x_lowest_sell_order.append(datetime.datetime.now()) self.y_lowest_sell_order.append(lowest_sell) #if len(sell_amounts) > 1: # then we have a meaningful "high" order ## todo: something with this data #highest_sell = max(sell_amounts) if buy_amounts: highest_buy = max(buy_amounts) self.x_highest_buy_order.append(datetime.datetime.now()) self.y_highest_buy_order.append(highest_buy) #if len(buy_amounts) > 1: # then we have a meaningful "high" order ## todo: something with this data #lowest_buy = min(buy_amounts) # ----------------------------------------------------- if "orderbook" in data: self.orderbook = data["orderbook"] def draw_graph(self): print("------------- drawing graph ------------") self.x_low, self.x_hi = self.ax[0].get_xlim() self.y_low, self.y_hi = self.ax[0].get_ylim() self.ax[0].clear() print("cleared self.ax[0]") if self.x_price and self.y_price: self.line_price.set_data(self.x_price, self.y_price) self.ax[0].add_line(self.line_price) if self.x_bought and self.y_bought: # self.boughtScatter.set_offsets((self.x_bought, self.y_bought)) self.boughtScatter = self.ax[0].scatter(self.x_bought, self.y_bought, color="lime", marker="P", s=100) if self.x_sold and self.y_sold: # self.scatter_sold.set_offsets((self.x_sold, self.y_sold)) self.scatter_sold = self.ax[0].scatter(self.x_sold, self.y_sold, color="salmon", marker="D", s=100) if self.x_lowest_sell_order and self.y_lowest_sell_order: self.line_lowest_sell_order.set_data(self.x_lowest_sell_order, self.y_lowest_sell_order) self.ax[0].add_line(self.line_lowest_sell_order) if self.x_highest_buy_order and self.y_highest_buy_order: self.line_highest_buy_order.set_data(self.x_highest_buy_order, self.y_highest_buy_order) self.ax[0].add_line(self.line_highest_buy_order) try: self.draw_depth() except: pass self.format_graph() self.canvas.draw() def format_graph(self): try: this_window_size = max(int(self.x_axis_window_size_input.get()[0]), 5) except: this_window_size = 50 if True: if self.x_axis_auto_scroll.optState.get(): if len(self.x_price) > this_window_size: self.ax[0].set_xlim(self.x_price[-1 * this_window_size + 1], self.x_price[-1]) # self.ax[0].autoscale(axis="y") self.ax[0].set_ylim(self.y_price[-1] * .85, self.y_price[-1] * 1.15) else: # self.ax[0].autoscale(axis="y") self.ax[0].set_ylim(self.y_price[-1] * .85, self.y_price[-1] * 1.15) self.ax[0].set_xlim(self.x_price[0], self.x_price[-1]) else: print("trying: ", self.x_low, self.x_hi, self.y_low, self.y_hi) self.ax[0].set_xlim(self.x_low, self.x_hi) self.ax[0].set_ylim(self.y_low, self.y_hi) self.ax[0].grid(color='gray', linestyle='--', linewidth=.5) #self.ax[0].set_xticklabels([str(d) for d in self.x_price]) self.ax[0].set_title(self.parent.name, fontsize=10) hfmt = matplotlib.dates.DateFormatter('%H:%M:%S') self.ax[0].xaxis.set_major_formatter(hfmt) self.ax[0].tick_params(axis='x', labelsize=8) #self.ax[0].set_xlim(self.x_price[0], self.x_price[-1]) self.fig.autofmt_xdate() def check_dates(self,dates): for d in dates: print(d.isoformat(),datetime.datetime.toordinal(d)) if not isinstance(d,datetime.date): raise Exception("Found bad date: %s %s " % (type(d),d)) def refresh(self, data, active=True): ''' :param data: a dictionary that comes from bot update method. todo: agree on format for data :return: ''' try: self.ingest_data(data) self.calc_stats() if active: self.draw_graph() except Exception as e: print(str(e)) raise finally: if False: duration = time.time() - start this_delay = int(max((self.delay - duration * 1000), 100)) # be at least 100 ms, assumes past behavior predicts future ;) print("duration of graph refresh: ", duration) self._root().after(this_delay, self.refresh, self.fake_data())
class Bot(ttk.Frame): def __init__(self, app, parent, owner, persist=None, stub=False, auto_start=False, starting_stats=None, *args, **kwargs): ttk.Frame.__init__(self, parent, style="app.TFrame", *args, **kwargs) self.app = app # root self.parent = parent # containing frame self.owner = owner self.stub = stub self.is_active = False self.title_var = tk.StringVar() self.coin_title = "coin" self.base_title = "base" self.exchange_title = "<exchange>" if self.stub: self.name = "XMR/BTC Stub" else: self.name = "New Merkato" self.title_var.set(str(self.name)) # merkato args #self.auth_frame = ttk.Frame(self, style="app.TFrame") self.bot = None if persist: self.name = persist["coin"] + "/" + persist[ "base"] + " " + persist["configuration"]["exchange"] self.title_var.set(str(self.name)) self.bot = Merkato(**persist) #presumably from db # -------------------- self.exchange_frame = ttk.Frame(self, style="app.TFrame") self.exchange_menu, self.exchange_index = database_utils.get_all_exchanges( ) self.exchange_name = MyWidget(self.app, self.exchange_frame, handle="exchange", startVal="test", choices=self.exchange_menu) self.coin = MyWidget(self.app, self.exchange_frame, handle="coin", startVal="XMR", choices=["XMR", "LTC", "ETH", "DOGE", "PEPECASH"]) self.base = MyWidget(self.app, self.exchange_frame, handle="base", startVal="BTC", choices=["BTC", "USDT"]) #self.public_key = MyWidget(self.app, self.exchange_frame, handle="pub. key", choices="entry") #self.private_key = MyWidget(self.app, self.exchange_frame, handle="priv. key", is_password=True, choices="entry") self.ask_budget = MyWidget(self.app, self.exchange_frame, handle="coin reserve", startVal=636, choices="entry") self.bid_budget = MyWidget(self.app, self.exchange_frame, handle="base reserve", startVal=10, choices="entry") self.spread = MyWidget(self.app, self.exchange_frame, handle="spread [%]", startVal=5.0, choices="entry") self.margin = MyWidget(self.app, self.exchange_frame, handle="profit margin [%]", startVal="0", choices=[str(i) for i in range(101)]) self.execute = ttk.Button(self.exchange_frame, text="Launch", cursor="shuttle", command=self.start) self.exchange_name.grid(row=0, column=0, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.coin.grid(row=1, column=0, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.base.grid(row=2, column=0, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) #self.public_key.grid(row=3, column=0, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) #self.private_key.grid(row=4, column=0, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.ask_budget.grid(row=5, column=0, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.bid_budget.grid(row=6, column=0, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.spread.grid(row=7, column=0, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.margin.grid(row=8, column=0, sticky=tk.NE, padx=(10, 5), pady=(5, 5)) self.execute.grid(row=9, column=0, sticky=tk.NE, padx=(10, 5), pady=(15, 5)) # -------------------- self.util_frame = ttk.Frame(self, style="app.TFrame") self.kill_button = ttk.Button(self.util_frame, text="Kill", cursor="shuttle", command=self.kill) self.kill_button.grid(row=0, column=0, sticky=tk.SE, padx=(10, 5), pady=(15, 5)) self.add_assets_type = MyWidget( self.app, self.util_frame, handle="Add Asset", startVal="XMR", choices=["XMR", "BTC", "ETH", "DOGE", "PEPECASH"]) self.add_assets_type.grid(row=1, column=0, sticky=tk.SE, padx=(10, 5), pady=(15)) self.add_assets_amount = MyWidget(self.app, self.util_frame, handle="amount to add", startVal=1.0, choices="entry") self.add_assets_amount.grid(row=2, column=0, sticky=tk.SE, padx=(10, 5), pady=(15)) self.add_assets_button = ttk.Button(self.util_frame, text="Add Assets", cursor="shuttle", command=self.add_assets) self.add_assets_button.grid(row=3, column=0, sticky=tk.SE, padx=(10, 5), pady=(15)) # -------------------- if not starting_stats: starting_stats = {"price_x": []} self.graph = Graph(self.app, self, stub=self.stub, **starting_stats) self.graph.grid(row=0, column=0, rowspan=3, padx=(5, 10)) #self.auth_frame.grid(row = 0, column=1, sticky=tk.NE, padx=(10,10), pady=(20,5)) if not self.bot: self.exchange_frame.grid(row=0, column=1, sticky=tk.NE, padx=(10, 10), pady=(20, 5)) self.util_frame.grid(row=1, column=1, sticky=tk.SE, padx=(10, 10), pady=(10, 5)) def add_assets(self): add_assets_amount = self.add_assets_amount.get()[0] add_assets_type = self.add_assets_type.get()[0] self.bot.update_orders(add_assets_type, add_assets_amount) def update(self, initial_update=False): context = {} if self.stub or self.bot: # then we have something to update print("--------------- updating %s ----------------------" % self.name) if not self.stub: if self.bot.initialized: if initial_update == False: context = self.bot.update() if initial_update == True: print('doing initial update') context = self.bot.get_context_history() print('adding bid_reserved_balance') context['ask_reserved_balance'] = float( self.bot.ask_reserved_balance) context['bid_reserved_balance'] = float( self.bot.bid_reserved_balance) context['quote_volume'] = float(self.bot.quote_volume) context['base_volume'] = float(self.bot.base_volume) context['spread'] = float(self.bot.spread) else: context = self.graph.fake_data() if context: self.graph.refresh(data=context, active=self.is_active) try: self.title_var.set(str(self.name)) except: self.title_var.set(str(self.name) + " err") def start(self): for widget in [ self.exchange_name, self.coin, self.base, self.ask_budget, self.bid_budget ]: print("{}:\t\t{}".format(widget.handle, widget.get()[0])) self.merk_args = {} self.merk_args["configuration"] = konfig.decrypt_keys( self.exchange_index[self.exchange_name.get()[0]], self.owner.password) self.merk_args["coin"] = self.coin.get()[0] self.merk_args["base"] = self.base.get()[0] self.merk_args["ask_reserved_balance"] = float( self.ask_budget.get()[0]) self.merk_args["bid_reserved_balance"] = float( self.bid_budget.get()[0]) self.merk_args["spread"] = float(self.spread.get()[0]) / 100.0 self.merk_args["profit_margin"] = float(self.margin.get()[0]) / 100.0 self.merk_args["user_interface"] = self self.coin_title = self.merk_args["coin"] self.base_title = self.merk_args["base"] self.graph.profit_base.config(text="%s \u0394bal:" % self.base_title[:4]) self.graph.profit_alt.config(text="%s \u0394bal:" % self.coin_title[:4]) self.exchange_title = self.merk_args["configuration"]["exchange"] self.name = str(self.merk_args["coin"]) + "/" + str( self.merk_args["base"]) + " " + self.exchange_title self.title_var.set(str(self.name)) if not self.stub: try: self.bot = Merkato(**self.merk_args) self.update(initial_update=True) except Exception as e: raise Exception('bot failed to start', e) e2 = traceback.format_exc() safe_show = self.merk_args.copy() safe_show["configuration"] = "obfuscated: " + str( safe_show["configuration"]["exchange"]) MessageBox.showerror("Bot Start Fail", str(e2) + "\n" + repr(self.merk_args)) else: self.exchange_frame.destroy() def kill(self): # TODO: tell self.bot to cancel all orders and delete merkato from DB if self.bot: self.bot.kill() # merkato.kill() self.bot = None # garbage collect mMerkato object, basically self._root().after(10, self.owner.kill_screen, self) # remove from gui def confirm_price(self, price): self.confirmation = popupWindow(self.app, "Confirm starting price: %s" % price, price) self.app.wait_window(self.confirmation.top) price = self.confirmation.value return price # if not exchange_config: # # get args via gui # pass #self.bot = Merkato(exchange_config) """