From 6de269601b87ff18c57eb3956d5121a499436424 Mon Sep 17 00:00:00 2001 From: iamredbar Date: Sun, 6 Dec 2020 15:09:55 -0600 Subject: [PATCH] UI Update and Pool Updater - added chart for easier visualization of pool vs. market - added update_pools.py for automated pool updating --- .gitignore | 2 + controller.py | 10 ++- depthchart.py | 189 +++++++++++++++++++++++++++++++++++++++++++++++ model.py | 115 ++++++++++++++++++---------- pool.py | 111 ++++++++++++++++++++++++++++ requirements.txt | 6 +- settings.yml | 65 ++++++++-------- update_pools.py | 26 +++++++ view.py | 184 +++++++++++++++++++++++++++++++++------------ 9 files changed, 584 insertions(+), 124 deletions(-) create mode 100644 depthchart.py create mode 100644 pool.py create mode 100644 update_pools.py diff --git a/.gitignore b/.gitignore index 9ba28b4..5c9f948 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ .DS_Store __pycache__/model.cpython-38.pyc __pycache__/view.cpython-38.pyc +__pycache__/depthchart.cpython-38.pyc +__pycache__/pool.cpython-38.pyc diff --git a/controller.py b/controller.py index c629c94..6115751 100644 --- a/controller.py +++ b/controller.py @@ -1,6 +1,6 @@ from view import View from model import Model -import tkinter as tk +from tkinter import Tk from pubsub import pub class Controller: @@ -15,8 +15,8 @@ def __init__(self, window): pub.subscribe(self.update_prices, 'update_prices') pub.subscribe(self.take_offer, 'take_offer') pub.subscribe(self.quit_program_requested, 'quit_program_requested') + pub.subscribe(self.asset_of_interest_change, 'asset_of_interest_change') pub.subscribe(self.deposit_lp, 'deposit_lp') - pub.subscribe(self.update_gui, 'update_gui') pub.subscribe(self.update_trading_prices, 'update_trading_prices') pub.subscribe(self.print_transaction, 'print_transaction') @@ -47,6 +47,9 @@ def update_prices(self, data): def pool_change_requested(self, data): self.model.pool_change(data) + def asset_of_interest_change(self, data): + self.model.asset_of_interest_change(data) + def take_offer(self, data): self.model.take_offer(data) @@ -54,7 +57,7 @@ def quit_program_requested(self): self.model.quit_program() if __name__ == '__main__': - window = tk.Tk() + window = Tk() window.title('PoolTool') window.resizable(False, False) window.columnconfigure([1,2], weight=1) @@ -65,7 +68,6 @@ def quit_program_requested(self): windowHeight = window.winfo_reqheight() positionRight = int(window.winfo_screenwidth()/2 - windowWidth/2) positionDown = int(window.winfo_screenheight()/3 - windowHeight/2) - window.geometry('+{}+{}'.format(positionRight, positionDown)) window.mainloop() diff --git a/depthchart.py b/depthchart.py new file mode 100644 index 0000000..ce5db89 --- /dev/null +++ b/depthchart.py @@ -0,0 +1,189 @@ +# by Christopher Sanborn +import tkinter as tk +from tkinter import ttk +import math +import numpy as numpy +import matplotlib +from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg +from matplotlib.figure import Figure + +from bitshares import BitShares +from bitshares.amount import Amount +from bitshares.asset import Asset + + +matplotlib.use("TkAgg") + +class DepthData(): + + def __init__(self): + self.dirty=True + + def update_blockchain_data(self, blockchain_data): + self.dirty = True + self.pool = blockchain_data['pool'] + self.amount_x = self.pool.amount_x() + self.amount_y = self.pool.amount_y() + self.bids = self.pool.market_bids() + self.asks = self.pool.market_asks() + + def get_pool_price(self): + return self.pool.price() + + def get_pool_buys(self, p_min, p_max): + p_pool = self.get_pool_price() + p_min = p_min if p_min > 0 else (p_max-p_min)/1e6 + p_max = min(p_max, p_pool) + prices = numpy.linspace(p_min,p_max,100) if p_min= p_min: + previous = cum + cum = cum + pr['quote']['amount'] + x.extend([price, price]) + y.extend([previous, cum]) + if cum > 0: + x.append(p_min) + y.append(cum) + return { + 'x':x, + 'y':y + } + + def get_book_sells(self, p_min, p_max): + x = [] + y = [] + cum = 0 + for pr in self.asks: + price = pr.price + if price <= p_max: + previous = cum + cum = cum + pr['quote']['amount'] + x.extend([price, price]) + y.extend([previous, cum]) + if cum > 0: + x.append(p_max) + y.append(cum) + return { + 'x':x, + 'y':y + } + + +class DepthChart(tk.Frame): + + def __init__(self, parent, controller, **kwargs): + tk.Frame.__init__(self, parent, **kwargs) + self.data = DepthData() + self.fig = None + self.canvas = None + + def update_blockchain_data(self, blockchain_data): + self.data.update_blockchain_data(blockchain_data) + pool_price = self.data.get_pool_price() + prices = [] + prices.extend([pr.price for pr in blockchain_data['market_orderbook']['asks']]) + self.pricewindow = [pool_price*(1/2), + pool_price*(3/2)] + self.draw() + + def draw(self): + + pool_sell_curve = self.data.get_pool_sells(*self.pricewindow) + pool_buy_curve = self.data.get_pool_buys(*self.pricewindow) + book_sell_curve = self.data.get_book_sells(*self.pricewindow) + book_buy_curve = self.data.get_book_buys(*self.pricewindow) + + if self.fig is None: + self.fig = Figure(figsize=(7,4.5)) + self.fig.clf() + self.fig.patch.set_facecolor("burlywood") + a = self.fig.gca() + a.set_facecolor("ghostwhite") + + attr = { + "book": { + "buy": { + "line": { + "color": "darkgreen", + }, + "area": { + "color": "darkgreen", + "alpha": 0.25, + }, + }, + "sell": { + "line": { + "color": "darkred", + }, + "area": { + "color": "darkred", + "alpha": 0.25, + }, + }, + }, + "pool": { + "buy": { + "line": { + "color": "green", + }, + "area": { + "color": "green", + "alpha": 0.25, + }, + }, + "sell": { + "line": { + "color": "red", + }, + "area": { + "color": "red", + "alpha": 0.25, + }, + }, + }, + } + + a.plot(pool_sell_curve['x'], pool_sell_curve['y'], **attr['pool']['sell']['line']) + a.plot(pool_buy_curve['x'], pool_buy_curve['y'], **attr['pool']['buy']['line']) + a.fill_between(pool_sell_curve['x'], pool_sell_curve['y'], **attr['pool']['sell']['area']) + a.fill_between(pool_buy_curve['x'], pool_buy_curve['y'], **attr['pool']['buy']['area']) + + a.plot(book_sell_curve['x'], book_sell_curve['y'], **attr['book']['sell']['line']) + a.plot(book_buy_curve['x'], book_buy_curve['y'], **attr['book']['buy']['line']) + a.fill_between(book_sell_curve['x'], book_sell_curve['y'], **attr['book']['sell']['area']) + a.fill_between(book_buy_curve['x'], book_buy_curve['y'], **attr['book']['buy']['area']) + + a.set_xlim(self.pricewindow) + a.set_ylim(bottom=0) + a.ticklabel_format(style='plain') + + a.set_title(self.data.pool.market().get_string(separator=":"), loc="left") + a.set_ylabel("Depth (%s)"%(self.data.pool.asset_y()['symbol'])) + a.set_xlabel("Price (%s/%s)"%(self.data.pool.asset_x()['symbol'], + self.data.pool.asset_y()['symbol'])) + + if self.canvas is None: + self.canvas = FigureCanvasTkAgg(self.fig, self) + self.canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True) + self.canvas.draw() diff --git a/model.py b/model.py index 87c6367..f8f4cd7 100644 --- a/model.py +++ b/model.py @@ -2,12 +2,12 @@ import yaml import re import sys - from bitshares import BitShares from bitshares.amount import Amount from bitshares.asset import Asset from bitshares.market import Market from bitshares.price import Price +from pool import Pool class Model: def __init__(self): @@ -32,6 +32,31 @@ def update_prices(self, data): else: selected_asset = data['assets'][1] unselected_asset = data['assets'][0] + market = Market('{}:{}'.format(selected_asset, unselected_asset)) + market_cost_track = { + 'total': 0, + 'cost': 0 + } + for order in (market.orderbook()['asks'] if data['buy_or_sell'] == 'buy' else market.orderbook()['bids']): + if (order['quote'].amount + market_cost_track['total']) <= data['amount']: + market_cost_track['total'] += order['quote'].amount + market_cost_track['cost'] += order['base'].amount + else: + order_difference = data['amount'] - market_cost_track['total'] + market_cost_track['total'] += order_difference + self._order_price = order['price'] + final_amount_cost = self.correct_market_precision( + order_difference, + order['price'], + order['quote'].symbol, + market_cost_track['cost'] + ) + market_cost_track['cost'] = final_amount_cost + break + # exchange preserves x*y + # buying subtracts from that side of the pool + # selling adds to that side of the pool + ################## lots of repeating code in this section, needs cleanup pool_cost_track = {'invariant': data['invariant']} if data['buy_or_sell'] == 'buy': if selected_asset == data['assets'][0]: @@ -69,6 +94,7 @@ def update_prices(self, data): pool_cost_track['pool_cost'] = output_amount pool_cost_track['asset'] = unselected_asset pub.sendMessage('update_trading_prices', data={ + 'market': '{} {}'.format(market_cost_track['cost'], order['base'].symbol), 'pool': '{} {}'.format(pool_cost_track['pool_cost'], pool_cost_track['asset']) }) @@ -86,7 +112,13 @@ def correct_pool_amount(self, higher_amount, lower_amount, asset): return float(round(difference, precision)) def pool_change(self, data): - self.get_blockchain_info(data) + self.pool_id_or_sym = data + self.get_blockchain_info() + + def asset_of_interest_change(self, sel): + self.invert = True if sel==0 else False + if self.pool_id_or_sym is not None: + self.get_blockchain_info() def deposit_lp(self, data): trade_message = '' @@ -108,50 +140,56 @@ def deposit_lp(self, data): new_data['operation_results'] = trade_message['operation_results'] except Exception as err: print(err) - new_data['paid_x'] = Amount(new_data['operation_results'][0][1]['paid'][0]) - new_data['paid_y'] = Amount(new_data['operation_results'][0][1]['paid'][1]) - new_data['received'] = Amount(new_data['operation_results'][0][1]['received'][0]) - pub.sendMessage('print_deposit', data=new_data) + if new_data: + try: + new_data['paid_x'] = Amount(new_data['operation_results'][0][1]['paid'][0]) + new_data['paid_y'] = Amount(new_data['operation_results'][0][1]['paid'][1]) + new_data['received'] = Amount(new_data['operation_results'][0][1]['received'][0]) + pub.sendMessage('print_deposit', data=new_data) + except: + print('error parsing deposit operation results') + else: + print('deposit operation failed') def take_offer(self, data): + bitshares = BitShares(nobroadcast=False, keys=data['key'], blocking='head') trade_message = '' new_data = {} - try: - bitshares = BitShares(nobroadcast=False, keys=data['key'], blocking='head') - if data['market_or_pool'] == 'pool': - new_data['operation_type'] = 'Pool Operation' - if data['buy_or_sell'] == 'buy': - amount_to_sell = Amount(data['expected_price']) - new_data['anticipated'] = Amount('{} {}'.format(data['amount_to_buy_sell'], data['selected_asset'])) - min_to_receive = new_data['anticipated'] * .993 - trade_message = bitshares.exchange_with_liquidity_pool( - pool=data['pool_id'], - amount_to_sell=amount_to_sell, - min_to_receive=min_to_receive, - account=data['account'], - ) - else: - amount_to_sell = Amount('{} {}'.format(data['amount_to_buy_sell'], data['selected_asset'])) - new_data['anticipated'] = Amount(data['expected_price']) - min_to_receive = new_data['anticipated'] * .993 - trade_message = bitshares.exchange_with_liquidity_pool( - pool=data['pool_id'], - amount_to_sell=amount_to_sell, - min_to_receive=min_to_receive, - account=data['account'], - ) - new_data['operation_results'] = trade_message['operation_results'] - new_data['paid'] = Amount(new_data['operation_results'][0][1]['paid'][0]) - new_data['received'] = Amount(new_data['operation_results'][0][1]['received'][0]) - except: + if data['market_or_pool'] == 'pool': + new_data['operation_type'] = 'Pool Operation' + if data['buy_or_sell'] == 'buy': + amount_to_sell = Amount(data['expected_price']) + new_data['anticipated'] = Amount('{} {}'.format(data['amount_to_buy_sell'], data['selected_asset'])) + min_to_receive = new_data['anticipated'] * .993 + trade_message = bitshares.exchange_with_liquidity_pool( + pool=data['pool_id'], + amount_to_sell=amount_to_sell, + min_to_receive=min_to_receive, + account=data['account'], + ) + else: + amount_to_sell = Amount('{} {}'.format(data['amount_to_buy_sell'], data['selected_asset'])) + new_data['anticipated'] = Amount(data['expected_price']) + min_to_receive = new_data['anticipated'] * .993 + trade_message = bitshares.exchange_with_liquidity_pool( + pool=data['pool_id'], + amount_to_sell=amount_to_sell, + min_to_receive=min_to_receive, + account=data['account'], + ) + new_data['operation_results'] = trade_message['operation_results'] + new_data['paid'] = Amount(new_data['operation_results'][0][1]['paid'][0]) + new_data['received'] = Amount(new_data['operation_results'][0][1]['received'][0]) + # still not working quite right + else: # market trade pass pub.sendMessage('print_transaction', data=new_data) - def get_blockchain_info(self, asset): + def get_blockchain_info(self): try: - data = {'pool': asset} - data['pool_object'] = self.bitshares.rpc.get_object(asset) + data = {'pool': Pool(self.pool_id_or_sym, invert=self.invert)} + data['pool_object'] = data['pool']['object'] data['pool_name'] = Asset(data['pool_object']['share_asset']).symbol data['asset_x'] = Asset(data['pool_object']['asset_a']) data['asset_y'] = Asset(data['pool_object']['asset_b']) @@ -169,6 +207,7 @@ def get_blockchain_info(self, asset): quote=data['asset_x'] ).orderbook(50) data['pool_invariant'] = int(data['pool_object']['virtual_value'])/(10**(data['asset_x'].precision + data['asset_y'].precision)) + #print(f"Invariant: {data['pool_invariant']}") # python bitshares reverses base and quote data['price_xy'] = Price(base=data['amount_y'], quote=data['amount_x']) @@ -177,4 +216,4 @@ def get_blockchain_info(self, asset): pub.sendMessage('update_gui', data=data) except Exception as err: print('Invalid pool selected. Error: {}'.format(err)) - pub.sendMessage('invalid_pool') + pub.sendMessage('invalid_pool') \ No newline at end of file diff --git a/pool.py b/pool.py new file mode 100644 index 0000000..23d291f --- /dev/null +++ b/pool.py @@ -0,0 +1,111 @@ +# by Christopher Sanborn +import math +import numpy +from bitshares import BitShares +from bitshares.amount import Amount +from bitshares.asset import Asset +from bitshares.market import Market +from bitshares.price import Order + +from bitshares.instance import BlockchainInstance + +@BlockchainInstance.inject +class Pool(dict): + + def __init__(self, *args, invert=False, **kwargs): + self.invert = invert + pool = kwargs.pop("pool", None) + if pool is None and len(args) == 1: + pool = args[0] + pool_id = self.blockchain._find_liquidity_pool(pool) + pool_obj = self.blockchain.rpc.get_object(pool_id) + data = { + "id": pool_id, + "object": pool_obj, # raw object here + # interpretted fields t.b.d. here by _populate method + } + dict.__init__(self, data) + self._populate() + + def __str__(self): + return " balances %s, %s"%( + self["asset_b"]["symbol"], + self["asset_a"]["symbol"], + self["id"], + self["amount_a"], + self["amount_b"], + ) + + def _populate(self): + self.update({ + "asset_a": Asset(self["object"]["asset_a"]), + "asset_b": Asset(self["object"]["asset_b"]), + "share_asset": Asset(self["object"]["share_asset"]), + "taker_fee": int(self["object"]["taker_fee_percent"]) / 10000, + }) + share_ddo = self.blockchain.rpc.get_object(self["share_asset"]["dynamic_asset_data_id"]) + self.update({ + "amount_a": Amount(int(self["object"]["balance_a"])/10**self["asset_a"].precision, self["asset_a"]), + "amount_b": Amount(int(self["object"]["balance_b"])/10**self["asset_b"].precision, self["asset_b"]), + }) + + def price(self): + """ Return nominal price to buy asset_b paying asset_a, unless + invert then flip. Return type: float (not a Price object). + + """ + return ( + self['amount_a']['amount'] / self['amount_b']['amount'] + if not self.invert else + self['amount_b']['amount'] / self['amount_a']['amount'] + ) + + def asset_x(self): + return (self['asset_a'] if not self.invert else self['asset_b']) + + def asset_y(self): + return (self['asset_b'] if not self.invert else self['asset_a']) + + def amount_x(self): + return ( + self['amount_a']['amount'] if not self.invert + else self['amount_b']['amount'] + ) + + def amount_y(self): + return ( + self['amount_b']['amount'] if not self.invert + else self['amount_a']['amount'] + ) + + def market(self): + return Market(**( + {"base":self['asset_a'],"quote":self['asset_b']} if not self.invert + else {"base":self['asset_b'],"quote":self['asset_a']} + )) + + def market_asks(self): + limits = self.market().get_limit_orders(300) + asks = [] + for lim in limits: + if lim['for_sale']['asset'] == self.asset_y(): + order = Order( + 1.0/lim['price'], + quote = lim['for_sale'], + base = Amount(lim['for_sale']['amount']/lim['price'], self.asset_x()) + ) + asks.append(order) + return sorted(asks, key = lambda k: k['price']) + + def market_bids(self): + limits = self.market().get_limit_orders(300) + bids = [] + for lim in limits: + if lim['for_sale']['asset'] == self.asset_x(): + order = Order( + 1.0/lim['price'], + base = lim['for_sale'], + quote = Amount(lim['for_sale']['amount']/lim['price'], self.asset_y()) + ) + bids.append(order) + return sorted(bids, key = lambda k: k['price'], reverse=True) diff --git a/requirements.txt b/requirements.txt index 97a4ba4..be98ea6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,7 @@ -uptick==0.2.6 +uptick==0.2.5 bitshares==0.7.0 -graphenelib>=1.4.0 +graphenelib==1.4.0 PyYAML pypubsub +matplotlib +numpy \ No newline at end of file diff --git a/settings.yml b/settings.yml index 1024701..6da17dc 100644 --- a/settings.yml +++ b/settings.yml @@ -1,33 +1,34 @@ ---- valid_assets: - - '1.19.0' - - '1.19.1' - - '1.19.2' - - '1.19.3' - - '1.19.4' - - '1.19.5' - - '1.19.6' - - '1.19.7' - - '1.19.8' - - '1.19.9' - - '1.19.13' - - '1.19.14' - - '1.19.15' - - '1.19.16' - - '1.19.17' - - '1.19.18' - - '1.19.19' - - '1.19.21' - - '1.19.22' - - '1.19.23' - - '1.19.24' - - '1.19.25' - - '1.19.26' - - '1.19.27' - - '1.19.28' - - '1.19.29' - - '1.19.30' - - '1.19.31' - - '1.19.32' - - '1.19.33' - - '1.19.35' +- 1.19.0 +- 1.19.1 +- 1.19.2 +- 1.19.3 +- 1.19.4 +- 1.19.5 +- 1.19.6 +- 1.19.7 +- 1.19.8 +- 1.19.9 +- 1.19.13 +- 1.19.14 +- 1.19.15 +- 1.19.16 +- 1.19.17 +- 1.19.18 +- 1.19.19 +- 1.19.21 +- 1.19.22 +- 1.19.23 +- 1.19.24 +- 1.19.25 +- 1.19.26 +- 1.19.27 +- 1.19.28 +- 1.19.29 +- 1.19.30 +- 1.19.31 +- 1.19.32 +- 1.19.33 +- 1.19.35 +- 1.19.36 +- 1.19.37 diff --git a/update_pools.py b/update_pools.py new file mode 100644 index 0000000..8405c36 --- /dev/null +++ b/update_pools.py @@ -0,0 +1,26 @@ +from bitshares import BitShares +import yaml + +if __name__ == '__main__': + base_id = '1.19.' + count = 0 + invalid_running_count = 0 + end = False + valid_pools = {'valid_assets': []} + bs = BitShares() + while end is not True: + pool_id = base_id + str(count) + pool_obj = bs.rpc.get_object(pool_id) + if pool_obj != None: + invalid_running_count = 0 + valid_pools['valid_assets'].append(pool_id) + else: + invalid_running_count += 1 + + if invalid_running_count > 4: + end = True + + count += 1 + + with open('settings.yml', 'w') as yml: + yaml.dump(valid_pools, yml) \ No newline at end of file diff --git a/view.py b/view.py index 9144bb9..fa2a9f4 100644 --- a/view.py +++ b/view.py @@ -3,6 +3,7 @@ from tkinter import messagebox from tkinter import simpledialog from pubsub import pub +from depthchart import DepthChart class View: def __init__(self, window): @@ -23,15 +24,17 @@ def create_widgets(self): self.frame_pool_info = tk.Frame( self.window, ) - self.frame_exchange = tk.Frame( + self.frame_market_info = tk.Frame( self.window, - background='#c9c9c9', ) - self.frame_pooltool_helper = tk.Frame( - self.frame_exchange, + self.frame_depthchart = DepthChart( + self.window, + None, + height=100, ) - self.frame_pooltool_lower = tk.Frame( - self.frame_exchange, + self.frame_pooltool_helper = tk.Frame( + self.window, + #background='#c9c9c9', ) self.frame_deposit = tk.Frame( self.window, @@ -63,6 +66,22 @@ def create_widgets(self): self.lbl_pool_price_ba = tk.Label(self.frame_pool_info) self.lbl_pool_price_ba['textvariable'] = self.string_var['sv_lbl_pool_price_ba'] + # market info widgets + self.lbl_assets = tk.Label(self.frame_market_info) + self.lbl_assets['textvariable'] = self.string_var['sv_lbl_assets'] + self.lbl_market_percentage_change = tk.Label(self.frame_market_info) + self.lbl_market_percentage_change['textvariable'] = self.string_var['sv_lbl_market_percentage_change'] + self.lbl_latest_price = tk.Label(self.frame_market_info) + self.lbl_latest_price['textvariable'] = self.string_var['sv_lbl_latest_price'] + self.lbl_highest_bid = tk.Label(self.frame_market_info, bg=self.palette('green')) + self.lbl_highest_bid['textvariable'] = self.string_var['sv_lbl_highest_bid'] + self.lbl_lowest_ask = tk.Label(self.frame_market_info, bg=self.palette('red')) + self.lbl_lowest_ask['textvariable'] = self.string_var['sv_lbl_lowest_ask'] + self.lbl_market_base_volume = tk.Label(self.frame_market_info) + self.lbl_market_base_volume['textvariable'] = self.string_var['sv_lbl_market_base_volume'] + self.lbl_market_quote_volume = tk.Label(self.frame_market_info) + self.lbl_market_quote_volume['textvariable'] = self.string_var['sv_lbl_market_quote_volume'] + # pooltool helper widgets self.rd_buy = ttk.Radiobutton( self.frame_pooltool_helper, @@ -86,7 +105,6 @@ def create_widgets(self): self.frame_pooltool_helper, width=10, state='disabled', - justify='center', ) self.ls_assets = tk.Listbox( self.frame_pooltool_helper, @@ -95,22 +113,37 @@ def create_widgets(self): width=10, state='disabled', ) - self.lbl_pool_price_only = tk.Label( - self.frame_pooltool_lower, - text='Pool Price:' + self.ls_assets.bind('<>',self.change_asset) + self.rd_use_market = ttk.Radiobutton( + self.frame_pooltool_helper, + text='Use Market =', + variable=self.string_var['rd_market_or_pool'], + value='market', + state='disabled' + ) + self.rd_use_pool = ttk.Radiobutton( + self.frame_pooltool_helper, + text='Use Pool =', + variable=self.string_var['rd_market_or_pool'], + value='pool', + state='disabled', + ) + self.lbl_helper_market_price = tk.Label( + self.frame_pooltool_helper, + textvariable=self.string_var['lbl_helper_market_price'] ) self.lbl_helper_pool_price = tk.Label( - self.frame_pooltool_lower, - textvariable=self.string_var['lbl_helper_pool_price'], + self.frame_pooltool_helper, + textvariable=self.string_var['lbl_helper_pool_price'] ) self.btn_update_trade_prices = ttk.Button( - self.frame_pooltool_lower, - text='Update Price', + self.frame_pooltool_helper, + text='Update Prices', command=self.update_prices, state='disabled', ) self.btn_take_offer = ttk.Button( - self.frame_pooltool_lower, + self.frame_pooltool_helper, text='Take Offer', command=self.take_offer, state='disabled', @@ -158,13 +191,21 @@ def create_widgets(self): textvariable=self.string_var['lbl_poolshare_symbol'] ) + def create_menu(self): + menubar = tk.Menu(self.window) + menu_file = tk.Menu(menubar, tearoff=0) + menu_file.add_command(label='Quit', command=self.quit_program) + menubar.add_cascade(label='File', menu=menu_file) + self.window.config(menu=menubar) + self.window.config + def setup_layout(self): # frames - self.frame_pool_info.grid(row=0, column=0, padx=5, pady=5, sticky='nw') - self.frame_exchange.grid(row=1, column=0, padx=5, pady=5) - self.frame_pooltool_helper.grid(row=0, column=0, padx=5, pady=5) - self.frame_pooltool_lower.grid(row=1, column=0, padx=5, pady=5) - self.frame_deposit.grid(row=2, column=0, padx=5, pady=5) + self.frame_pool_info.grid(row=0, column=0, columnspan=2, padx=5, pady=5, sticky='nw') + self.frame_market_info.grid(row=0, column=2, columnspan=2, padx=5, pady=5, sticky='ne') + self.frame_depthchart.grid(row=1, column=0, columnspan=4, padx=5, pady=5, stick='ew') + self.frame_pooltool_helper.grid(row=2, column=1, columnspan=2, padx=5, pady=5) + self.frame_deposit.grid(row=3, column=1, columnspan=2, padx=5, pady=5) self.frame_deposit_upper.grid(row=0, column=0, padx=5, pady=5) self.frame_deposit_lower.grid(row=1, column=0, padx=5, pady=5) @@ -177,16 +218,26 @@ def setup_layout(self): self.lbl_pool_price_ab.grid(row=5, column=0, padx=5, sticky='w') self.lbl_pool_price_ba.grid(row=6, column=0, padx=5, sticky='w') + # market info + self.lbl_assets.grid(row=0, column=0, padx=5, sticky='e') + self.lbl_latest_price.grid(row=3, column=0, padx=5, sticky='e') + self.lbl_highest_bid.grid(row=4, column=0, padx=5, sticky='ew') + self.lbl_lowest_ask.grid(row=5, column=0, padx=5, sticky='ew') + self.lbl_market_base_volume.grid(row=6, column=0, padx=5, sticky='e') + self.lbl_market_quote_volume.grid(row=7, column=0, padx=5, sticky='e') + # pooltool helper self.rd_buy.grid(row=0, column=0, padx=5) self.rd_sell.grid(row=1, column=0, padx=5) - self.ls_assets.grid(row=0, rowspan=2, column=1, padx=5) - self.lbl_trade_amount.grid(row=0, column=2, padx=5) - self.ent_trade_amount.grid(row=1, column=2, padx=5) - self.lbl_pool_price_only.grid(row=0, column=0, padx=5, pady=5) - self.lbl_helper_pool_price.grid(row=1, column=0, padx=5, sticky='ew') - self.btn_update_trade_prices.grid(row=0, column=1, padx=5) - self.btn_take_offer.grid(row=1, column=1, padx=5, sticky='ew') + self.lbl_trade_amount.grid(row=0, column=1, padx=5) + self.ent_trade_amount.grid(row=1, column=1, padx=5) + self.ls_assets.grid(row=0, rowspan=2, column=2, padx=5) + self.rd_use_market.grid(row=0, column=3, padx=5, sticky='ew') + self.rd_use_pool.grid(row=1, column=3, padx=5, sticky='ew') + self.lbl_helper_market_price.grid(row=0, column=4, padx=5, sticky='ew') + self.lbl_helper_pool_price.grid(row=1, column=4, padx=5, sticky='ew') + self.btn_update_trade_prices.grid(row=0, column=5, padx=5) + self.btn_take_offer.grid(row=1, column=5, padx=5, sticky='ew') # deposit section self.ent_assetx_amount.grid(row=0, column=0, padx=5, pady=5) @@ -205,10 +256,18 @@ def get_string_var(self): self.string_var['sv_lbl_pool_invariant'] = tk.StringVar() self.string_var['sv_lbl_pool_price_ab'] = tk.StringVar() self.string_var['sv_lbl_pool_price_ba'] = tk.StringVar() + self.string_var['sv_lbl_assets'] = tk.StringVar() + self.string_var['sv_lbl_market_percentage_change'] = tk.StringVar() + self.string_var['sv_lbl_latest_price'] = tk.StringVar() + self.string_var['sv_lbl_highest_bid'] = tk.StringVar() + self.string_var['sv_lbl_lowest_ask'] = tk.StringVar() + self.string_var['sv_lbl_market_base_volume'] = tk.StringVar() + self.string_var['sv_lbl_market_quote_volume'] = tk.StringVar() self.string_var['rd_buy_sell'] = tk.StringVar() self.string_var['ls_assets'] = tk.StringVar() self.string_var['rd_market_or_pool'] = tk.StringVar() + self.string_var['lbl_helper_market_price'] = tk.StringVar() self.string_var['lbl_helper_pool_price'] = tk.StringVar() self.string_var['lbl_assetx_deposit'] = tk.StringVar() @@ -224,11 +283,19 @@ def assign_string_var(self): self.string_var['sv_lbl_pool_invariant'].set('Invariant (k=xy):') self.string_var['sv_lbl_pool_price_ab'].set('X/Y Price:') self.string_var['sv_lbl_pool_price_ba'].set('Y/X Price:') + self.string_var['sv_lbl_assets'].set('(Market X/Y)') + self.string_var['sv_lbl_market_percentage_change'].set('(Market % Change)') + self.string_var['sv_lbl_latest_price'].set('Latest Price:') + self.string_var['sv_lbl_highest_bid'].set('Highest Bid:') + self.string_var['sv_lbl_lowest_ask'].set('Lowest Ask:') + self.string_var['sv_lbl_market_base_volume'].set('24h Base Volume:') + self.string_var['sv_lbl_market_quote_volume'].set('24h Quote Volume:') self.string_var['rd_buy_sell'].set('buy') self.string_var['ls_assets'].set(['Asset X', 'Asset Y']) self.string_var['rd_market_or_pool'].set('pool') - self.string_var['lbl_helper_pool_price'].set('0 BTS') + self.string_var['lbl_helper_market_price'].set('(Market Price)') + self.string_var['lbl_helper_pool_price'].set('(Pool Price)') self.string_var['lbl_assetx_deposit'].set('Asset X') self.string_var['lbl_assety_deposit'].set('Asset y') @@ -245,9 +312,18 @@ def update_gui(self, data): self.string_var['sv_lbl_pool_invariant'].set('Invariant (k=xy): {}'.format(data['pool_invariant'])) self.string_var['sv_lbl_pool_price_ab'].set('X/Y Price: {}'.format(data['price_xy'])) self.string_var['sv_lbl_pool_price_ba'].set('Y/X Price: {}'.format(data['price_yx'])) + self.string_var['sv_lbl_assets'].set('{}/{}'.format(data['asset_x'].symbol, data['asset_y'].symbol)) + self.string_var['sv_lbl_market_percentage_change'].set('{}%'.format(data['market_ticker_object']['percentChange'])) + self.string_var['sv_lbl_latest_price'].set('Latest Price: {}'.format(data['market_ticker_object']['latest'])) + self.string_var['sv_lbl_highest_bid'].set('Highest Bid: {}'.format(data['market_ticker_object']['highestBid'])) + self.string_var['sv_lbl_lowest_ask'].set('Lowest Ask: {}'.format(data['market_ticker_object']['lowestAsk'])) + self.string_var['sv_lbl_market_base_volume'].set('24hr Base Volume: {}'.format(data['market_ticker_object']['baseVolume'])) + self.string_var['sv_lbl_market_quote_volume'].set('24hr Quote Volume: {}'.format(data['market_ticker_object']['quoteVolume'])) self.string_var['ls_assets'].set([data['asset_x'].symbol, data['asset_y'].symbol]) - self.string_var['lbl_helper_pool_price'].set('0 BTS') + self.string_var['lbl_helper_market_price'].set('') + self.string_var['lbl_helper_pool_price'].set('') + self.frame_depthchart.update_blockchain_data(data) self.string_var['lbl_assetx_deposit'].set(data['asset_x'].symbol) self.string_var['lbl_assety_deposit'].set(data['asset_y'].symbol) @@ -257,8 +333,8 @@ def update_gui(self, data): self.rd_sell['state'] = 'normal' self.ent_trade_amount['state'] = 'normal' self.ls_assets['state'] = 'normal' + self.rd_use_pool['state'] = 'normal' self.btn_update_trade_prices['state'] = 'enabled' - self.btn_take_offer['state'] = 'enabled' self.ent_assetx_amount['state'] = 'normal' self.ent_assety_amount['state'] = 'normal' @@ -281,6 +357,11 @@ def change_pool(self, event): data=self.cmb_pool_id['values'][self.cmb_pool_id.current()] ) + def change_asset(self, event): + sel_tuple = event.widget.curselection() + sel = 0 if (len(sel_tuple) and sel_tuple[0] == 0) else 1 + pub.sendMessage('asset_of_interest_change', data=sel) + def update_shares(self): pass @@ -311,7 +392,7 @@ def deposit_to_lp(self): def take_offer(self): data = { - 'market_or_pool': 'pool', + 'market_or_pool': self.string_var['rd_market_or_pool'].get(), 'buy_or_sell': self.string_var['rd_buy_sell'].get(), 'amount_to_buy_sell': self.ent_trade_amount.get(), 'selected_asset': self.ls_assets.get(self.ls_assets.curselection()), @@ -337,17 +418,16 @@ def take_offer(self): pub.sendMessage('take_offer', data=data) def print_transaction(self, data): - if len(data) != 0: - messagebox.showinfo( - 'Trade Data', - '{}\nPaid: {}\nAnticipated: {}\nReceived: {}'.format( - data['operation_type'], - data['paid'], - data['anticipated'], - data['received'] - ), - parent=self.window, - ) + messagebox.showinfo( + 'Trade Data', + '{}\nPaid: {}\nAnticipated: {}\nReceived: {}'.format( + data['operation_type'], + data['paid'], + data['anticipated'], + data['received'] + ), + parent=self.window + ) def print_deposit(self, data): if len(data) != 0: @@ -401,21 +481,29 @@ def update_prices(self): data['invariant'] = float(self.string_var['sv_lbl_pool_invariant'].get()[18:]) data['selected_asset'] = self.ls_assets.curselection()[0] pub.sendMessage('update_prices', data=data) + self.btn_take_offer['state'] = 'enabled' + + def update_trading_prices(self, data): + self.string_var['lbl_helper_market_price'].set(data['market']) + self.string_var['lbl_helper_pool_price'].set(data['pool']) def invalid_pool(self): self.loading_pop_up.destroy() self.window.update() messagebox.showinfo( 'Error', - 'Invalid pool selection. Please try a different pool.', + 'Invalid pool selection. Pool was likely deleted or has a zero balance somewhere. Please try a different pool.', parent=self.window, ) - def update_trading_prices(self, data): - self.string_var['lbl_helper_pool_price'].set(data['pool']) - def quit_program(self): pub.sendMessage('quit_program_requested') -if __name__ == '__main__': - pass + def palette(self, item): + color_palette = { + 'header': '#333333', + 'body': '#1E1E1E', + 'green': '#69872D', + 'red': '#DF413A' + } + return color_palette[item] \ No newline at end of file