From c48c2fb685a4545f7aac3fa7eeb4d49e96b6e1e1 Mon Sep 17 00:00:00 2001 From: Therneel Date: Wed, 10 Jun 2020 10:21:47 +0200 Subject: [PATCH 1/5] added wallet model, presenter and viewer --- wallet_model.py | 60 +++++++++++++++++++++++++++++++++++++++++++++ wallet_presenter.py | 58 +++++++++++++++++++++++++++++++++++++++++++ wallet_viewer.py | 52 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 wallet_model.py create mode 100644 wallet_presenter.py create mode 100644 wallet_viewer.py diff --git a/wallet_model.py b/wallet_model.py new file mode 100644 index 00000000..a6017e53 --- /dev/null +++ b/wallet_model.py @@ -0,0 +1,60 @@ +import requests +import json + +wallet_data = {'base_currency': "", 'data': {}} + +def calculate_currency_value(bids, amount): + value = 0.0 + for bid in bids: + rate = min(amount, bid['amount']) + value += rate * bid['value'] + amount -= rate + if amount == 0: + return value + +def check_currency_availability(currency): + url = 'https://api.bittrex.com/v3/markets' + headers = {'content-type': 'application/json'} + response = requests.request("GET", url, headers=headers) + dic = response.json() + for market in dic: + if market['baseCurrencySymbol'] == currency: + return True + return False + +def get_bids(currency): + url = 'https://api.bittrex.com/api/v1.1/public/getorderbook?market={0}-{1}&type=both'.format(wallet_data['base_currency'], currency) + headers = {'content-type': 'application/json'} + response = requests.request("GET", url, headers=headers) + dic = response.json() + if dic['success'] == True: + bids = [] + for bid in dic['result']['sell']: + bids.append({'amount': bid['Quantity'], 'value': bid['Rate']}) + return bids + else: + return None + +def add_currency(currency, amount): + bids = get_bids(currency) + if bids is not None: + value = calculate_currency_value(bids, amount) + wallet_data['data'][currency] = {'amount': amount, 'value': value} + print(wallet_data) + return True + return False + +def remove_currency(currency, amount): + if currency in wallet_data['data']: + del wallet_data['data'][currency] + return True + return False + +def set_base_currency(currency): + if check_currency_availability(currency): + wallet_data['base_currency'] = currency + return True + return False + +def get_wallet_data(): + return wallet_data diff --git a/wallet_presenter.py b/wallet_presenter.py new file mode 100644 index 00000000..527c9350 --- /dev/null +++ b/wallet_presenter.py @@ -0,0 +1,58 @@ +import wallet_viewer as viewer +import wallet_model as wallet + + +''' +TODO: +1. auto-save data +2. load data at startup +3. auto-refresh values +''' + +def add_currency(currency, amount): + if wallet.add_currency(currency, float(amount)): + update_view_display() + else: + viewer.error_display("Currency doesn't exist in this exchange") + +def set_currency(currency, amount): + add_currency(currency, amount) + +def remove_currency(currency): + if wallet.remove_currency(currency): + update_view_display() + else: + viewer.error_display("You don't have such currency") + +def set_base_currency(currency): + if wallet.set_base_currency(currency): + #update_view_display() + print() + else: + viewer.error_display("Currency doesn't exist in this exchange") + viewer.get_base_currency_dialog() + +def update_view_display(): + wallet_data = wallet.get_wallet_data() + wallet_display_text = "" + print(wallet_data['data']) + for currency, info in wallet_data['data'].items(): + wallet_display_text += "{}: {:.4f} | {:.4f} {}\n".format(currency, info['amount'], info['value'], wallet_data['base_currency']) + viewer.update_display(wallet_display_text) + +def update_database(): + print() + +def update_currencies_value(): + print() + +def thread(): + #TODO + update_database() + update_currencies_value() + +def main(): + viewer.create_main_window() + +if __name__ == "__main__": + main() diff --git a/wallet_viewer.py b/wallet_viewer.py new file mode 100644 index 00000000..8f8f2999 --- /dev/null +++ b/wallet_viewer.py @@ -0,0 +1,52 @@ +from tkinter import simpledialog, messagebox +import wallet_presenter as presenter +import tkinter as tk + + +window = tk.Tk() +wallet_info = tk.StringVar(value="") + +def add_currency_dialog(): + currency = simpledialog.askstring('Data', 'Enter the currency you want to add', parent=window) + amount = simpledialog.askstring('Data', 'Enter currency amount', parent=window) + presenter.add_currency(currency, amount) + +def set_currency_dialog(): + currency = simpledialog.askstring('Data', 'Enter the currency you want to modify', parent=window) + amount = simpledialog.askstring('Data', 'Enter new currency amount', parent=window) + presenter.set_currency(currency, amount) + +def remove_currency_dialog(): + currency = simpledialog.askstring('Data', 'Enter the currency u want to remove', parent=window) + presenter.remove_currency(currency, amount) + +def get_base_currency_dialog(): + currency = simpledialog.askstring('Data', 'Enter the base currency', parent=window) + if currency is not None and currency != '': + presenter.set_base_currency(currency) + #base_currency.set(value=f'Base currency: {wallet.base_currency}') + +def update_display(wallet_display_text): + basic_info = "Currency: Amount | Value\n" + wallet_info.set(basic_info + wallet_display_text) + +def error_display(error_info): + messagebox.askyesno("Error info", "") + messagebox.showerror(title="Error", message=error_info) + +def create_main_window(): + window.title("WALLET") + + get_base_currency_dialog() + lb_wallet_info = tk.Label(window, textvariable=wallet_info) + btn_add_currency = tk.Button(window, text='Add currency', command=add_currency_dialog) + btn_set_currency = tk.Button(window, text='Modify currency', command=set_currency_dialog) + btn_remove_currency = tk.Button(window, text='Remove currency', command=remove_currency_dialog) + btn_add_currency.pack() + btn_set_currency.pack() + btn_remove_currency.pack() + lb_wallet_info.pack() + + window.mainloop() + +create_main_window() From fd45b69c4a8b5c79f82524d958c78041eb813d96 Mon Sep 17 00:00:00 2001 From: Therneel Date: Wed, 10 Jun 2020 14:48:22 +0200 Subject: [PATCH 2/5] added save, load, thread functionality --- json_instrukcja.txt | 13 +++++++++++++ wallet.json | 1 + wallet_model.py | 38 ++++++++++++++++++++++++++++++++---- wallet_presenter.py | 47 ++++++++++++++++++++++++++------------------- wallet_viewer.py | 39 +++++++++++++++++++++---------------- 5 files changed, 97 insertions(+), 41 deletions(-) create mode 100644 json_instrukcja.txt create mode 100644 wallet.json diff --git a/json_instrukcja.txt b/json_instrukcja.txt new file mode 100644 index 00000000..b506bc4a --- /dev/null +++ b/json_instrukcja.txt @@ -0,0 +1,13 @@ +Aplikacja automatycznie generuje i zapisuje dane posiadanych walut portfela jako json. +Można także jednak wgrać do niego dane z zewnątrz mając na uwadze poniższy format: + +{"base_currency": "", +"data": + {"": + {"amount': 0.0, "value": 0.0}}, + "": + {"amount': 0.0, "value": 0.0}} +} + +np.: +{"base_currency": "USD", "data": {"BTC": {"amount": 2.3, "value": 22467.187803234367}, "LTC": {"amount": 0.1, "value": 4.5919}}} \ No newline at end of file diff --git a/wallet.json b/wallet.json new file mode 100644 index 00000000..5055b0bb --- /dev/null +++ b/wallet.json @@ -0,0 +1 @@ +{"base_currency": "USD", "data": {"BTC": {"amount": 2.3, "value": 22467.187803234367}, "LTC": {"amount": 0.1, "value": 4.5919}}} \ No newline at end of file diff --git a/wallet_model.py b/wallet_model.py index a6017e53..863735cc 100644 --- a/wallet_model.py +++ b/wallet_model.py @@ -2,6 +2,7 @@ import json wallet_data = {'base_currency': "", 'data': {}} +database_path = "wallet.json" def calculate_currency_value(bids, amount): value = 0.0 @@ -12,6 +13,10 @@ def calculate_currency_value(bids, amount): if amount == 0: return value +def update_currencies_values(data=wallet_data): + for currency, cur_info in data['data'].items(): + cur_info['value'] = calculate_currency_value(get_bids(data['base_currency'], currency), cur_info['amount']) + def check_currency_availability(currency): url = 'https://api.bittrex.com/v3/markets' headers = {'content-type': 'application/json'} @@ -22,8 +27,8 @@ def check_currency_availability(currency): return True return False -def get_bids(currency): - url = 'https://api.bittrex.com/api/v1.1/public/getorderbook?market={0}-{1}&type=both'.format(wallet_data['base_currency'], currency) +def get_bids(base_currency, currency): + url = 'https://api.bittrex.com/api/v1.1/public/getorderbook?market={0}-{1}&type=both'.format(base_currency, currency) headers = {'content-type': 'application/json'} response = requests.request("GET", url, headers=headers) dic = response.json() @@ -36,7 +41,7 @@ def get_bids(currency): return None def add_currency(currency, amount): - bids = get_bids(currency) + bids = get_bids(wallet_data['base_currency'], currency) if bids is not None: value = calculate_currency_value(bids, amount) wallet_data['data'][currency] = {'amount': amount, 'value': value} @@ -44,12 +49,21 @@ def add_currency(currency, amount): return True return False -def remove_currency(currency, amount): +def remove_currency(currency): if currency in wallet_data['data']: del wallet_data['data'][currency] return True return False +def change_currency_amount(currency, amount): + if currency in wallet_data['data']: + wallet_data['data'][currency]['amount'] += amount + if wallet_data['data'][currency]['amount'] < 0.0: + wallet_data['data'][currency]['amount'] = 0.0 + calculate_currency_value(get_bids(wallet_data['base_currency'], wallet_data['data'][currency]['amount'])) + return True + return False + def set_base_currency(currency): if check_currency_availability(currency): wallet_data['base_currency'] = currency @@ -58,3 +72,19 @@ def set_base_currency(currency): def get_wallet_data(): return wallet_data + +def load_database(): + global wallet_data + try: + with open(database_path) as json_file: + wallet_data = json.load(json_file) + if wallet_data['base_currency'] != "": + return True + except OSError: + update_database() + return False + return False + +def update_database(data=wallet_data): + with open(database_path, 'w') as json_file: + json.dump(data, json_file) diff --git a/wallet_presenter.py b/wallet_presenter.py index 527c9350..dd0a493b 100644 --- a/wallet_presenter.py +++ b/wallet_presenter.py @@ -1,14 +1,8 @@ +import threading +import time import wallet_viewer as viewer import wallet_model as wallet - -''' -TODO: -1. auto-save data -2. load data at startup -3. auto-refresh values -''' - def add_currency(currency, amount): if wallet.add_currency(currency, float(amount)): update_view_display() @@ -24,34 +18,47 @@ def remove_currency(currency): else: viewer.error_display("You don't have such currency") +def change_currency_amount(currency, amount): + if wallet.change_currency_amount(currency, float(amount)): + update_view_display() + else: + viewer.error_display("You don't have such currency") + def set_base_currency(currency): if wallet.set_base_currency(currency): - #update_view_display() print() else: viewer.error_display("Currency doesn't exist in this exchange") viewer.get_base_currency_dialog() +def update_data(): + wallet.update_database() + + def update_view_display(): wallet_data = wallet.get_wallet_data() wallet_display_text = "" - print(wallet_data['data']) + sum = 0 for currency, info in wallet_data['data'].items(): wallet_display_text += "{}: {:.4f} | {:.4f} {}\n".format(currency, info['amount'], info['value'], wallet_data['base_currency']) + sum += info['value'] + wallet_display_text += "\n\nIn total: {:.4f} {}".format(sum, wallet_data['base_currency']) viewer.update_display(wallet_display_text) -def update_database(): - print() - -def update_currencies_value(): - print() - -def thread(): - #TODO - update_database() - update_currencies_value() +def run(wallet_data): + while True: + time.sleep(5) + wallet.update_database(wallet_data) + wallet.update_currencies_values(wallet_data) + update_view_display() def main(): + if wallet.load_database() == True: + wallet.update_currencies_values() + update_view_display() + else: + viewer.get_base_currency_dialog() + threading.Thread(target=run, args=(wallet.get_wallet_data(),)).start() viewer.create_main_window() if __name__ == "__main__": diff --git a/wallet_viewer.py b/wallet_viewer.py index 8f8f2999..7ea08100 100644 --- a/wallet_viewer.py +++ b/wallet_viewer.py @@ -6,47 +6,52 @@ window = tk.Tk() wallet_info = tk.StringVar(value="") +def simple_dialog(msg, function): + output = [] + for request in msg: + output.append(simpledialog.askstring('Data', request, parent=window)) + if output[-1] == None: + return False + function(*output) + return True + def add_currency_dialog(): - currency = simpledialog.askstring('Data', 'Enter the currency you want to add', parent=window) - amount = simpledialog.askstring('Data', 'Enter currency amount', parent=window) - presenter.add_currency(currency, amount) + simple_dialog(['Enter the currency you want to add', 'Enter currency amount'], presenter.add_currency) def set_currency_dialog(): - currency = simpledialog.askstring('Data', 'Enter the currency you want to modify', parent=window) - amount = simpledialog.askstring('Data', 'Enter new currency amount', parent=window) - presenter.set_currency(currency, amount) + simple_dialog(['Enter the currency you want to modify', 'Enter new currency amount'], presenter.set_currency) + +def change_currency_amount_dialog(): + simple_dialog(['Enter the currency you want to modify', 'Enter currency modification amount'], presenter.change_currency_amount) def remove_currency_dialog(): - currency = simpledialog.askstring('Data', 'Enter the currency u want to remove', parent=window) - presenter.remove_currency(currency, amount) + simple_dialog(['Enter the currency u want to remove'], presenter.remove_currency) def get_base_currency_dialog(): currency = simpledialog.askstring('Data', 'Enter the base currency', parent=window) if currency is not None and currency != '': - presenter.set_base_currency(currency) - #base_currency.set(value=f'Base currency: {wallet.base_currency}') + presenter.add_currency(currency) def update_display(wallet_display_text): basic_info = "Currency: Amount | Value\n" wallet_info.set(basic_info + wallet_display_text) def error_display(error_info): - messagebox.askyesno("Error info", "") messagebox.showerror(title="Error", message=error_info) def create_main_window(): - window.title("WALLET") + window.title("Crypto wallet") + window.geometry("250x300") - get_base_currency_dialog() lb_wallet_info = tk.Label(window, textvariable=wallet_info) btn_add_currency = tk.Button(window, text='Add currency', command=add_currency_dialog) - btn_set_currency = tk.Button(window, text='Modify currency', command=set_currency_dialog) + btn_set_currency = tk.Button(window, text='Set currency amount', command=set_currency_dialog) + btn_change_currency_amount =tk.Button(window, text='Change currency amount', command=change_currency_amount_dialog) btn_remove_currency = tk.Button(window, text='Remove currency', command=remove_currency_dialog) btn_add_currency.pack() - btn_set_currency.pack() + #btn_set_currency.pack() + btn_change_currency_amount.pack() btn_remove_currency.pack() lb_wallet_info.pack() window.mainloop() - -create_main_window() From 87f908dff98ad97fcb6fdf594bf168a3ff2ec775 Mon Sep 17 00:00:00 2001 From: Therneel Date: Wed, 10 Jun 2020 15:29:58 +0200 Subject: [PATCH 3/5] added new exchange support --- wallet_model.py | 53 ++++++++++++++++++++++++++++++--------------- wallet_presenter.py | 3 +-- wallet_viewer.py | 4 ++-- 3 files changed, 39 insertions(+), 21 deletions(-) diff --git a/wallet_model.py b/wallet_model.py index 863735cc..30305c9a 100644 --- a/wallet_model.py +++ b/wallet_model.py @@ -4,6 +4,16 @@ wallet_data = {'base_currency': "", 'data': {}} database_path = "wallet.json" +markets = { + 'bitbay': 'https://api.bitbay.net/rest/trading/ticker', + 'bittrex': 'https://api.bittrex.com/v3/markets', +} + +exchanges = { + 'bitbay': 'https://bitbay.net/API/Public/{0}{1}/orderbook.json', + 'bittrex': 'https://api.bittrex.com/api/v1.1/public/getorderbook?market={1}-{0}&type=both', +} + def calculate_currency_value(bids, amount): value = 0.0 for bid in bids: @@ -18,27 +28,36 @@ def update_currencies_values(data=wallet_data): cur_info['value'] = calculate_currency_value(get_bids(data['base_currency'], currency), cur_info['amount']) def check_currency_availability(currency): - url = 'https://api.bittrex.com/v3/markets' - headers = {'content-type': 'application/json'} - response = requests.request("GET", url, headers=headers) - dic = response.json() - for market in dic: - if market['baseCurrencySymbol'] == currency: - return True + for exchange, api_url in exchanges.items(): + headers = {'content-type': 'application/json'} + response = requests.request("GET", url, headers=headers) + dic = response.json() + if exchange is "bitbay": + for market in dic: + if market['market']['first']['currency'] == currency: + return True + elif exchange is 'bittrex': + for market in dic: + if market['baseCurrencySymbol'] == currency: + return True return False def get_bids(base_currency, currency): - url = 'https://api.bittrex.com/api/v1.1/public/getorderbook?market={0}-{1}&type=both'.format(base_currency, currency) - headers = {'content-type': 'application/json'} - response = requests.request("GET", url, headers=headers) - dic = response.json() - if dic['success'] == True: + for exchange, url in exchanges.items(): + formated_url = url.format(currency, base_currency) + headers = {'content-type': 'application/json'} + response = requests.request("GET", formated_url, headers=headers) + dic = response.json() bids = [] - for bid in dic['result']['sell']: - bids.append({'amount': bid['Quantity'], 'value': bid['Rate']}) - return bids - else: - return None + if exchange is 'bitbay' and 'bids' in dic.keys(): + for bid in dic['bids']: + bids.append({'amount': bid[1], 'value': bid[0]}) + return bids + elif exchange is 'bittrex' and dic['success'] == True: + for bid in dic['result']['sell']: + bids.append({'amount': bid['Quantity'], 'value': bid['Rate']}) + return bids + return None def add_currency(currency, amount): bids = get_bids(wallet_data['base_currency'], currency) diff --git a/wallet_presenter.py b/wallet_presenter.py index dd0a493b..f36ceef8 100644 --- a/wallet_presenter.py +++ b/wallet_presenter.py @@ -26,7 +26,7 @@ def change_currency_amount(currency, amount): def set_base_currency(currency): if wallet.set_base_currency(currency): - print() + update_view_display() else: viewer.error_display("Currency doesn't exist in this exchange") viewer.get_base_currency_dialog() @@ -34,7 +34,6 @@ def set_base_currency(currency): def update_data(): wallet.update_database() - def update_view_display(): wallet_data = wallet.get_wallet_data() wallet_display_text = "" diff --git a/wallet_viewer.py b/wallet_viewer.py index 7ea08100..40715b8d 100644 --- a/wallet_viewer.py +++ b/wallet_viewer.py @@ -41,7 +41,7 @@ def error_display(error_info): def create_main_window(): window.title("Crypto wallet") - window.geometry("250x300") + window.geometry("250x250") lb_wallet_info = tk.Label(window, textvariable=wallet_info) btn_add_currency = tk.Button(window, text='Add currency', command=add_currency_dialog) @@ -49,7 +49,7 @@ def create_main_window(): btn_change_currency_amount =tk.Button(window, text='Change currency amount', command=change_currency_amount_dialog) btn_remove_currency = tk.Button(window, text='Remove currency', command=remove_currency_dialog) btn_add_currency.pack() - #btn_set_currency.pack() + btn_set_currency.pack() btn_change_currency_amount.pack() btn_remove_currency.pack() lb_wallet_info.pack() From ebddc5b87533bd4c2f3356e88595eced7708ee35 Mon Sep 17 00:00:00 2001 From: Therneel Date: Wed, 10 Jun 2020 16:06:12 +0200 Subject: [PATCH 4/5] fixed minor errors --- wallet_model.py | 12 +++++++----- wallet_viewer.py | 4 +++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/wallet_model.py b/wallet_model.py index 30305c9a..78591856 100644 --- a/wallet_model.py +++ b/wallet_model.py @@ -4,6 +4,8 @@ wallet_data = {'base_currency': "", 'data': {}} database_path = "wallet.json" +currency_hierarchy = ["USD", "BTC"] + markets = { 'bitbay': 'https://api.bitbay.net/rest/trading/ticker', 'bittrex': 'https://api.bittrex.com/v3/markets', @@ -28,17 +30,17 @@ def update_currencies_values(data=wallet_data): cur_info['value'] = calculate_currency_value(get_bids(data['base_currency'], currency), cur_info['amount']) def check_currency_availability(currency): - for exchange, api_url in exchanges.items(): + for exchange, url in markets.items(): headers = {'content-type': 'application/json'} response = requests.request("GET", url, headers=headers) dic = response.json() - if exchange is "bitbay": - for market in dic: - if market['market']['first']['currency'] == currency: + if exchange is "bitbay" and dic['status'] is "Ok": + for market in dic['items']: + if market['market']['first']['currency'] == currency or market['market']['second']['currency'] == currency: return True elif exchange is 'bittrex': for market in dic: - if market['baseCurrencySymbol'] == currency: + if market['baseCurrencySymbol'] == currency or market['quoteCurrencySymbol'] == currency: return True return False diff --git a/wallet_viewer.py b/wallet_viewer.py index 40715b8d..65111f07 100644 --- a/wallet_viewer.py +++ b/wallet_viewer.py @@ -30,7 +30,7 @@ def remove_currency_dialog(): def get_base_currency_dialog(): currency = simpledialog.askstring('Data', 'Enter the base currency', parent=window) if currency is not None and currency != '': - presenter.add_currency(currency) + presenter.set_base_currency(currency) def update_display(wallet_display_text): basic_info = "Currency: Amount | Value\n" @@ -48,10 +48,12 @@ def create_main_window(): btn_set_currency = tk.Button(window, text='Set currency amount', command=set_currency_dialog) btn_change_currency_amount =tk.Button(window, text='Change currency amount', command=change_currency_amount_dialog) btn_remove_currency = tk.Button(window, text='Remove currency', command=remove_currency_dialog) + btn_change_base_currency = tk.Button(window, text='Change base currency', command=get_base_currency_dialog) btn_add_currency.pack() btn_set_currency.pack() btn_change_currency_amount.pack() btn_remove_currency.pack() + btn_change_base_currency.pack() lb_wallet_info.pack() window.mainloop() From 97753fa03a40289156411e3cad689de3bbeac3b4 Mon Sep 17 00:00:00 2001 From: Therneel Date: Wed, 10 Jun 2020 16:18:09 +0200 Subject: [PATCH 5/5] fixed file encoding --- json_instrukcja.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/json_instrukcja.txt b/json_instrukcja.txt index b506bc4a..9a0c3861 100644 --- a/json_instrukcja.txt +++ b/json_instrukcja.txt @@ -1,5 +1,5 @@ -Aplikacja automatycznie generuje i zapisuje dane posiadanych walut portfela jako json. -Można także jednak wgrać do niego dane z zewnątrz mając na uwadze poniższy format: +Aplikacja automatycznie generuje i zapisuje dane posiadanych walut portfela jako json. +MoĹĽna takĹĽe jednak wgrać do niego dane z zewnÄ…trz majÄ…c na uwadze poniĹĽszy format: {"base_currency": "", "data":