import sys from getpass import getpass from inspect import signature import connection from connection import client_request from debug import debug from game import DEFAULT_ORDER_EXPIRY, CURRENCY_NAME, MIN_INTEREST_INTERVAL from routes import client_commands from run_client import fake_loading_bar from util import my_tabulate, yn_dialog exiting = False def login(username=None, password=None): if connection.session_id is not None: fake_loading_bar('Signing out', duration=0.7) connection.session_id = None if username is None: username = input('Username: ') if password is None: if sys.stdin.isatty(): password = getpass('Password: ') else: password = input('Password: ') fake_loading_bar('Signing in', duration=2.3) response = client_request('login', {"username": username, "password": password}) success = 'session_id' in response if success: connection.session_id = response['session_id'] print('Login successful.') else: if 'error' in response: print('Login failed with message:', response['error']) else: print('Login failed.') def register(username=None, game_key='', password=None, retype_pw=None): if connection.session_id is not None: connection.session_id = None fake_loading_bar('Signing out', duration=0.7) if username is None: username = input('Username: ') if password is None: if sys.stdin.isatty(): password = getpass('New password: ') retype_pw = getpass('Retype password: ') else: password = input('New password: ') retype_pw = input('Retype password: ') if password != retype_pw: print('Passwords do not match.') return elif retype_pw is None: if sys.stdin.isatty(): retype_pw = getpass('Retype password: ') else: retype_pw = input('Retype password: ') if password != retype_pw: print('Passwords do not match.') return if not debug: if game_key == '': print('Entering a game key will provide you with some starting money and other useful stuff.') game_key = input('Game key (leave empty if you don\'t have one): ') fake_loading_bar('Validating Registration', duration=5.2) if game_key != '': fake_loading_bar('Validating Game Key', duration=0.4) response = client_request('register', {"username": username, "password": password, "game_key": game_key}) if 'error' in response: print('Registration failed with message:', response['error']) def cancel_order(order_no=None): if order_no is None: order_no = input('Order No.: ') fake_loading_bar('Validating Request', duration=0.6) response = client_request('cancel_order', {"session_id": connection.session_id, "order_id": order_no}) if 'error' in response: print('Order cancelling failed with message:', response['error']) def change_pw(password=None, retype_pw=None): if password != retype_pw: password = None if password is None: if sys.stdin.isatty(): password = getpass('New password: ') retype_pw = getpass('Retype password: ') else: password = input('New password: ') retype_pw = input('Retype password: ') if password != retype_pw: print('Passwords do not match.') return elif retype_pw is None: if sys.stdin.isatty(): retype_pw = getpass('Retype password: ') else: retype_pw = input('Retype password: ') if password != retype_pw: print('Passwords do not match.') return fake_loading_bar('Validating password', duration=1.2) fake_loading_bar('Changing password', duration=5.2) response = client_request('change_password', {"session_id": connection.session_id, "password": password}) if 'error' in response: print('Changing password failed with message:', response['error']) fake_loading_bar('Signing out', duration=0.7) connection.session_id = None # noinspection PyShadowingBuiltins def help(): print('Allowed commands:') command_table = [] for cmd in client_commands: this_module = sys.modules[__name__] method = getattr(this_module, cmd) params = signature(method).parameters command_table.append([cmd] + [p for p in params]) print(my_tabulate(command_table, tablefmt='pipe', headers=['command', 'param 1', 'param 2', 'param 3', 'param 4', 'param 5', ])) print('NOTE:') print(' All parameters for all commands are optional!') print(' Commands can be combined in one line with ; between them.') print(' Parameters are separated with whitespace.') print(' Use . as a decimal separator.') print(' Use 0/1 for boolean parameters (other strings might work).') def depot(): fake_loading_bar('Loading data', duration=1.3) response = client_request('depot', {"session_id": connection.session_id}) success = 'data' in response and 'own_wealth' in response if success: data = response['data'] for row in data: row.append(row[1] * row[2]) print(my_tabulate(data, headers=['Object', 'Amount', 'Course', 'Bid', 'Ask', 'Est. Value'], tablefmt="pipe", floatfmt='.2f')) wealth = response['own_wealth'] print(f'Taking into account the amount of loans you have, this results in a wealth of roughly {wealth}.') if response['banking_license']: print(f'Also, you have a banking license.') else: if 'error' in response: print('Depot access failed with message:', response['error']) else: print('Depot access failed.') def leaderboard(): fake_loading_bar('Loading data', duration=1.3) response = client_request('leaderboard', {}) success = 'data' in response if success: print(my_tabulate(response['data'], headers=['Trader', 'Wealth'], tablefmt="pipe")) # print('Remember that the goal is to be as rich as possible, not to be richer than other traders!') else: if 'error' in response: print('Leaderboard access failed with message:', response['error']) else: print('Leaderboard access failed.') def activate_key(key=''): if key == '': print('Entering a game key may get you some money or other useful stuff.') key = input('Key: ') if key == '': print('Invalid key.') fake_loading_bar('Validating Key', duration=0.4) response = client_request('activate_key', {"session_id": connection.session_id, 'key': key}) if 'error' in response: print('Key activation failed with message:', response['error']) def _order(is_buy_order, obj_name, amount, limit, stop_loss, expiry): if stop_loss not in [None, '1', '0']: print('Invalid value for flag stop loss (only 0 or 1 allowed).') return if obj_name is None: # TODO list some available objects obj_name = input('Name of object to sell: ') if amount is None: amount = input('Amount: ') if limit is None: set_limit = yn_dialog('Do you want to place a limit?') if set_limit: limit = input('Limit: ') stop_loss = yn_dialog('Is this a stop-loss limit?') if limit is not None: try: limit = float(limit) except ValueError: print('Invalid limit.') return if stop_loss is None: stop_loss = yn_dialog('Is this a stop-loss limit?') question = 'Are you sure you want to use such a low limit (limit=' + str(limit) + ')?:' if not is_buy_order and limit <= 0 and not yn_dialog(question): print('Order was not placed.') return if expiry is None: expiry = input('Time until order expires (minutes, default ' + str(DEFAULT_ORDER_EXPIRY) + '):') if expiry == '': expiry = DEFAULT_ORDER_EXPIRY try: expiry = float(expiry) except ValueError: print('Invalid expiration time.') return fake_loading_bar('Sending Data', duration=1.3) response = client_request('order', { "buy": is_buy_order, "session_id": connection.session_id, "amount": amount, "ownable": obj_name, "limit": limit, "stop_loss": stop_loss, "time_until_expiration": expiry }) if 'error' in response: print('Order placement failed with message:', response['error']) else: print('You might want to use the `trades` or `depot` commands', 'to see if the order has been executed already.') def sell(obj_name=None, amount=None, limit=None, stop_loss=None, expiry=None): _order(is_buy_order=False, obj_name=obj_name, amount=amount, limit=limit, stop_loss=stop_loss, expiry=expiry) def buy(obj_name=None, amount=None, limit=None, stop_loss=None, expiry=None): _order(is_buy_order=True, obj_name=obj_name, amount=amount, limit=limit, stop_loss=stop_loss, expiry=expiry) def orders(): fake_loading_bar('Loading Data', duration=0.9) response = client_request('orders', {"session_id": connection.session_id}) success = 'data' in response if success: print(my_tabulate(response['data'], headers=['Buy?', 'Name', 'Size', 'Limit', 'stop-loss', 'Expires', 'No.'], tablefmt="pipe")) else: if 'error' in response: print('Order access failed with message:', response['error']) else: print('Order access failed.') def buy_banking_license(): fake_loading_bar('Loading data', duration=2.3) fake_loading_bar('Hiring some lawyers and consultants', duration=4.6) fake_loading_bar('Overcoming some bureaucratic hurdles', duration=8.95) fake_loading_bar('Filling the necessary forms', duration=14.4) fake_loading_bar('Waiting for bank regulation\'s response', duration=26.8) response = client_request('buy_banking_license', {"session_id": connection.session_id}) success = 'message' in response and 'error' not in response if success: print('Success. You are now a bank.') print() summarize_bank_rules() # print('Remember that the goal is to be as rich as possible, not to be richer than other traders!') else: if 'error' in response: print('Banking license application failed with message:', response['error']) else: print('Banking license application access failed.') def summarize_bank_rules(): # TODO rework this stuff, does not work like this in real life variables = _global_variables() banking_license_price = variables['banking_license_price'] marginal_lending_facility = variables['marginal_lending_facility'] cash_reserve_free_amount = variables['cash_reserve_free_amount'] cash_reserve_ratio = variables['cash_reserve_ratio'] deposit_facility = variables['deposit_facility'] print(f'A bank is by definition anyone who has a banking license.') print(f'A banking license can be for {banking_license_price} {CURRENCY_NAME}.') print(f'This includes payment of lawyers and consultants to deal with the formal application.') print() print(f'Banks are allowed to borrow money from the central bank at the marginal ' f'lending facility (currently {marginal_lending_facility * 100}% p.a.).') print(f'For every {CURRENCY_NAME} above {cash_reserve_free_amount} banks have to ' f'deposit a cash reserve of {cash_reserve_ratio * 100}% at the central bank.') print(f'Banks receive a deposit facility of {deposit_facility * 100}% p.a. for cash reserves.') def summarize_loan_rules(): variables = _global_variables() personal_loan_interest_rate = variables['personal_loan_interest_rate'] print(f'You can take personal loans at an interest rate of {personal_loan_interest_rate * 100}% p.a.') print(f'You can repay personal loans at any time if you have the liquidity.') print(f'Interest rates will be automatically be debited from your account.') print(f'Note that this debit may be delayed by up to {MIN_INTEREST_INTERVAL} seconds.') print(f'If you have no {CURRENCY_NAME} available (or negative account balance), you can still') print(f' - pay any further interests (account will move further into the negative)') print(f' - take a new loan (if we think that you will be able to repay it)') print(f' - sell any securities you own') print(f'However you can not') print(f' - spend money to buy securities') print(f' - spend money to buy a banking license') def take_out_personal_loan(amount=None): if amount is None: summarize_loan_rules() print() amount = input('Please enter your desired loan volume: ') try: amount = float(amount) except ValueError: print('Amount must be a number larger than 0.') return if amount <= 0: print('Amount must be a number larger than 0.') fake_loading_bar('Checking if you are trustworthy', duration=0.0) fake_loading_bar('Checking if you are credit-worthy', duration=0.0) fake_loading_bar('Transferring the money', duration=1.6) response = client_request('take_out_personal_loan', {"session_id": connection.session_id, 'amount': amount}) success = 'message' in response and 'error' not in response if success: print(f'You took a personal loan of {amount} {CURRENCY_NAME}.') else: if 'error' in response: print('Taking a personal loan failed with message:', response['error']) else: print('Taking a personal loan failed.') def loans(): fake_loading_bar('Loading Data', duration=0.9) response = client_request('loans', {"session_id": connection.session_id}) success = 'data' in response if success: for row in response['data']: row[-1] = f'{row[-1] * 100:.2f}%' print(my_tabulate(response['data'], headers=['Loan ID', 'Total amount', 'Remaining', 'Interest p.a.', ], floatfmt='.2f', tablefmt="pipe")) else: if 'error' in response: print('Order access failed with message:', response['error']) else: print('Order access failed.') def repay_loan(loan_id=None, amount=None): if loan_id is None: loans() print('Which loan would you like to pay back?') loan_id = input('Loan id:') if amount is None: print('How much would you like to pay back?') amount = input('Amount (type `all` for the remaining loan):') if amount != 'all': try: amount = float(amount) # this can also raise a ValueError if amount <= 0: raise ValueError except ValueError: print('Amount must be a number larger than 0 or \'all\' (for paying back the remaining loan).') return fake_loading_bar('Transferring the money', duration=1.7) response = client_request('repay_loan', {"session_id": connection.session_id, 'amount': amount, 'loan_id': loan_id}) success = 'message' in response and 'error' not in response if success: print(f'You repayed the specified amount of {CURRENCY_NAME}.') else: if 'error' in response: print('Repaying the loan failed with message:', response['error']) else: print('Repaying the loan failed.') def _global_variables(): return client_request('global_variables') def orders_on(obj_name=None): if obj_name is None: # TODO list some available objects obj_name = input('Name of object to check: ') fake_loading_bar('Loading Data', duration=2.3) response = client_request('orders_on', {"session_id": connection.session_id, "ownable": obj_name}) success = 'data' in response if success: print(my_tabulate(response['data'], headers=['My', 'Buy?', 'Name', 'Size', 'Limit', 'Expires', 'No.'], tablefmt="pipe")) else: if 'error' in response: print('Order access failed with message:', response['error']) else: print('Order access failed.') def gift(username=None, obj_name=None, amount=None): if username is None: username = input('Username of recipient: ') if obj_name is None: obj_name = input('Name of object to give: ') if amount is None: amount = input('How many?: ') fake_loading_bar('Sending Gift', duration=4.2) response = client_request('gift', {"session_id": connection.session_id, "username": username, "object_name": obj_name, "amount": amount}) if 'error' in response: print('Order access failed with message:', response['error']) elif 'message' in response: print(response['message']) def news(): fake_loading_bar('Loading Data', duration=0.76) response = client_request('news', {}) success = 'data' in response if success: print(my_tabulate(response['data'], headers=['Date', 'Title'], tablefmt="pipe")) else: if 'error' in response: print('News access failed with message:', response['error']) else: print('News access failed.') def tradables(): fake_loading_bar('Loading Data', duration=12.4) response = client_request('tradables', {}) success = 'data' in response if success: print(my_tabulate(response['data'], headers=['Name', 'Course', 'Market Cap.'], tablefmt="pipe")) world_wealth = 0 for row in response['data']: if row[2] is not None: world_wealth += row[2] print('Estimated worldwide wealth:', world_wealth) else: if 'error' in response: print('Data access failed with message:', response['error']) else: print('Data access failed.') def trades_on(obj_name=None, limit=5): limit = float(limit) if obj_name is None: # TODO list some available objects obj_name = input('Name of object to check: ') fake_loading_bar('Loading Data', duration=0.34 * limit) response = client_request('trades_on', {"session_id": connection.session_id, "ownable": obj_name, "limit": limit}) success = 'data' in response if success: print(my_tabulate(response['data'], headers=['Time', 'Volume', 'Price'], tablefmt="pipe")) else: if 'error' in response: print('Trades access failed with message:', response['error']) else: print('Trades access failed.') def trades(limit=10): limit = float(limit) fake_loading_bar('Loading Data', duration=limit * 0.21) response = client_request('trades', {"session_id": connection.session_id, "limit": limit}) success = 'data' in response if success: print(my_tabulate(response['data'], headers=['Buy?', 'Name', 'Volume', 'Price', 'Time'], tablefmt="pipe")) else: if 'error' in response: print('Trades access failed with message:', response['error']) else: print('Trades access failed.') def old_orders(include_canceled=None, include_executed=None, limit=10): limit = float(limit) if include_canceled is None: include_canceled = yn_dialog('Include canceled/expired orders in list?') if include_executed is None: include_executed = yn_dialog('Include fully executed orders in list?') fake_loading_bar('Loading Data', duration=limit * 0.27) response = client_request('old_orders', {"session_id": connection.session_id, "include_canceled": include_canceled, "include_executed": include_executed, "limit": limit}) success = 'data' in response if success: print(my_tabulate(response['data'], headers=['Buy?', 'Name', 'Size', 'Limit', 'Expiry', 'No.', 'Status'], tablefmt="pipe")) else: if 'error' in response: print('Order access failed with message:', response['error']) else: print('Order access failed.') # noinspection PyShadowingBuiltins def exit(): global exiting exiting = True