1
1

client_controller.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. import sys
  2. from getpass import getpass
  3. from inspect import signature
  4. import connection
  5. from connection import client_request
  6. from debug import debug
  7. from game import DEFAULT_ORDER_EXPIRY, CURRENCY_NAME
  8. from run_client import allowed_commands, fake_loading_bar
  9. from util import my_tabulate, yn_dialog
  10. exiting = False
  11. def login(username=None, password=None):
  12. if connection.session_id is not None:
  13. fake_loading_bar('Signing out', duration=0.7)
  14. connection.session_id = None
  15. if username is None:
  16. username = input('Username: ')
  17. if password is None:
  18. if sys.stdin.isatty():
  19. password = getpass('Password: ')
  20. else:
  21. password = input('Password: ')
  22. fake_loading_bar('Signing in', duration=2.3)
  23. response = client_request('login', {"username": username, "password": password})
  24. success = 'session_id' in response
  25. if success:
  26. connection.session_id = response['session_id']
  27. print('Login successful.')
  28. else:
  29. if 'error' in response:
  30. print('Login failed with message:', response['error'])
  31. else:
  32. print('Login failed.')
  33. def register(username=None, game_key='', password=None, retype_pw=None):
  34. if connection.session_id is not None:
  35. connection.session_id = None
  36. fake_loading_bar('Signing out', duration=0.7)
  37. if username is None:
  38. username = input('Username: ')
  39. if password is None:
  40. if sys.stdin.isatty():
  41. password = getpass('New password: ')
  42. retype_pw = getpass('Retype password: ')
  43. else:
  44. password = input('New password: ')
  45. retype_pw = input('Retype password: ')
  46. if password != retype_pw:
  47. print('Passwords do not match.')
  48. return
  49. elif retype_pw is None:
  50. if sys.stdin.isatty():
  51. retype_pw = getpass('Retype password: ')
  52. else:
  53. retype_pw = input('Retype password: ')
  54. if password != retype_pw:
  55. print('Passwords do not match.')
  56. return
  57. if not debug:
  58. if game_key == '':
  59. print('Entering a game key will provide you with some starting money and other useful stuff.')
  60. game_key = input('Game key (leave empty if you don\'t have one): ')
  61. fake_loading_bar('Validating Registration', duration=5.2)
  62. if game_key != '':
  63. fake_loading_bar('Validating Game Key', duration=0.4)
  64. response = client_request('register', {"username": username, "password": password, "game_key": game_key})
  65. if 'error' in response:
  66. print('Registration failed with message:', response['error'])
  67. def cancel_order(order_no=None):
  68. if order_no is None:
  69. order_no = input('Order No.: ')
  70. fake_loading_bar('Validating Request', duration=0.6)
  71. response = client_request('cancel_order', {"session_id": connection.session_id, "order_id": order_no})
  72. if 'error' in response:
  73. print('Order cancelling failed with message:', response['error'])
  74. def change_pw(password=None, retype_pw=None):
  75. if password != retype_pw:
  76. password = None
  77. if password is None:
  78. if sys.stdin.isatty():
  79. password = getpass('New password: ')
  80. retype_pw = getpass('Retype password: ')
  81. else:
  82. password = input('New password: ')
  83. retype_pw = input('Retype password: ')
  84. if password != retype_pw:
  85. print('Passwords do not match.')
  86. return
  87. elif retype_pw is None:
  88. if sys.stdin.isatty():
  89. retype_pw = getpass('Retype password: ')
  90. else:
  91. retype_pw = input('Retype password: ')
  92. if password != retype_pw:
  93. print('Passwords do not match.')
  94. return
  95. fake_loading_bar('Validating password', duration=1.2)
  96. fake_loading_bar('Changing password', duration=5.2)
  97. response = client_request('change_password', {"session_id": connection.session_id, "password": password})
  98. if 'error' in response:
  99. print('Changing password failed with message:', response['error'])
  100. fake_loading_bar('Signing out', duration=0.7)
  101. connection.session_id = None
  102. # noinspection PyShadowingBuiltins
  103. def help():
  104. print('Allowed commands:')
  105. command_table = []
  106. for cmd in allowed_commands:
  107. this_module = sys.modules[__name__]
  108. method = getattr(this_module, cmd)
  109. params = signature(method).parameters
  110. command_table.append([cmd] + [p for p in params])
  111. print(my_tabulate(command_table, tablefmt='pipe', headers=['command',
  112. 'param 1',
  113. 'param 2',
  114. 'param 3',
  115. 'param 4',
  116. 'param 5',
  117. ]))
  118. print('NOTE:')
  119. print(' All parameters for all commands are optional!')
  120. print(' Commands can be combined in one line with ; between them.')
  121. print(' Parameters are separated with whitespace.')
  122. print(' Use . as a decimal separator.')
  123. print(' Use 0/1 for boolean parameters (other strings might work).')
  124. def depot():
  125. fake_loading_bar('Loading data', duration=1.3)
  126. response = client_request('depot', {"session_id": connection.session_id})
  127. success = 'data' in response and 'own_wealth' in response
  128. if success:
  129. data = response['data']
  130. for row in data:
  131. row.append(row[1] * row[2])
  132. print(my_tabulate(data,
  133. headers=['Object', 'Amount', 'Course', 'Bid', 'Ask', 'Est. Value'],
  134. tablefmt="pipe"))
  135. wealth = response['own_wealth']
  136. print(f'This corresponds to a wealth of roughly {wealth}.')
  137. if response['banking_license']:
  138. print(f'Also, you have a banking license.')
  139. else:
  140. if 'error' in response:
  141. print('Depot access failed with message:', response['error'])
  142. else:
  143. print('Depot access failed.')
  144. def leaderboard():
  145. fake_loading_bar('Loading data', duration=1.3)
  146. response = client_request('leaderboard', {})
  147. success = 'data' in response
  148. if success:
  149. print(my_tabulate(response['data'], headers=['Trader', 'Wealth'], tablefmt="pipe"))
  150. # print('Remember that the goal is to be as rich as possible, not to be richer than other traders!')
  151. else:
  152. if 'error' in response:
  153. print('Leaderboard access failed with message:', response['error'])
  154. else:
  155. print('Leaderboard access failed.')
  156. def activate_key(key=''):
  157. if key == '':
  158. print('Entering a game key may get you some money or other useful stuff.')
  159. key = input('Key: ')
  160. if key == '':
  161. print('Invalid key.')
  162. fake_loading_bar('Validating Key', duration=0.4)
  163. response = client_request('activate_key', {"session_id": connection.session_id, 'key': key})
  164. if 'error' in response:
  165. print('Key activation failed with message:', response['error'])
  166. def _order(is_buy_order, obj_name, amount, limit, stop_loss, expiry):
  167. if stop_loss not in [None, '1', '0']:
  168. print('Invalid value for flag stop loss (only 0 or 1 allowed).')
  169. return
  170. if obj_name is None: # TODO list some available objects
  171. obj_name = input('Name of object to sell: ')
  172. if amount is None:
  173. amount = input('Amount: ')
  174. if limit is None:
  175. set_limit = yn_dialog('Do you want to place a limit?')
  176. if set_limit:
  177. limit = input('Limit: ')
  178. stop_loss = yn_dialog('Is this a stop-loss limit?')
  179. if limit is not None:
  180. try:
  181. limit = float(limit)
  182. except ValueError:
  183. print('Invalid limit.')
  184. return
  185. if stop_loss is None:
  186. stop_loss = yn_dialog('Is this a stop-loss limit?')
  187. question = 'Are you sure you want to use such a low limit (limit=' + str(limit) + ')?:'
  188. if not is_buy_order and limit <= 0 and not yn_dialog(question):
  189. print('Order was not placed.')
  190. return
  191. if expiry is None:
  192. expiry = input('Time until order expires (minutes, default ' + str(DEFAULT_ORDER_EXPIRY) + '):')
  193. if expiry == '':
  194. expiry = DEFAULT_ORDER_EXPIRY
  195. try:
  196. expiry = float(expiry)
  197. except ValueError:
  198. print('Invalid expiration time.')
  199. return
  200. fake_loading_bar('Sending Data', duration=1.3)
  201. response = client_request('order', {
  202. "buy": is_buy_order,
  203. "session_id": connection.session_id,
  204. "amount": amount,
  205. "ownable": obj_name,
  206. "limit": limit,
  207. "stop_loss": stop_loss,
  208. "time_until_expiration": expiry
  209. })
  210. if 'error' in response:
  211. print('Order placement failed with message:', response['error'])
  212. else:
  213. print('You might want to use the `trades` or `depot` commands',
  214. 'to see if the order has been executed already.')
  215. def sell(obj_name=None, amount=None, limit=None, stop_loss=None, expiry=None):
  216. _order(is_buy_order=False,
  217. obj_name=obj_name,
  218. amount=amount,
  219. limit=limit,
  220. stop_loss=stop_loss,
  221. expiry=expiry)
  222. def buy(obj_name=None, amount=None, limit=None, stop_loss=None, expiry=None):
  223. _order(is_buy_order=True,
  224. obj_name=obj_name,
  225. amount=amount,
  226. limit=limit,
  227. stop_loss=stop_loss,
  228. expiry=expiry)
  229. def orders():
  230. fake_loading_bar('Loading Data', duration=0.9)
  231. response = client_request('orders', {"session_id": connection.session_id})
  232. success = 'data' in response
  233. if success:
  234. print(my_tabulate(response['data'],
  235. headers=['Buy?', 'Name', 'Size', 'Limit', 'stop-loss', 'Expires', 'No.'],
  236. tablefmt="pipe"))
  237. else:
  238. if 'error' in response:
  239. print('Order access failed with message:', response['error'])
  240. else:
  241. print('Order access failed.')
  242. def buy_banking_license():
  243. fake_loading_bar('Loading data', duration=2.3)
  244. fake_loading_bar('Hiring some lawyers and consultants', duration=4.6)
  245. fake_loading_bar('Overcoming some bureaucratic hurdles', duration=8.95)
  246. fake_loading_bar('Filling the necessary forms', duration=14.4)
  247. fake_loading_bar('Waiting for bank regulation\'s response', duration=26.8)
  248. response = client_request('buy_banking_license', {"session_id": connection.session_id})
  249. success = 'data' in response
  250. if success:
  251. print('Success. You are now a bank.')
  252. variables = _global_variables()
  253. marginal_lending_facility = variables['marginal_lending_facility']
  254. cash_reserve_free_amount = variables['cash_reserve_free_amount']
  255. cash_reserve_ratio = variables['cash_reserve_ratio']
  256. print(f'You are now allowed to borrow money from the central bank at the marginal '
  257. f'lending facility (currently {marginal_lending_facility * 100}%).')
  258. print(f'For every {CURRENCY_NAME} above {cash_reserve_free_amount} you have to '
  259. f'deposit a cash reserve of {cash_reserve_ratio * 100}% at the central bank.')
  260. # print('Remember that the goal is to be as rich as possible, not to be richer than other traders!')
  261. else:
  262. if 'error' in response:
  263. print('Banking license application failed with message:', response['error'])
  264. else:
  265. print('Banking license application access failed.')
  266. def _global_variables():
  267. return client_request('global_variables')
  268. def orders_on(obj_name=None):
  269. if obj_name is None: # TODO list some available objects
  270. obj_name = input('Name of object to check: ')
  271. fake_loading_bar('Loading Data', duration=2.3)
  272. response = client_request('orders_on', {"session_id": connection.session_id, "ownable": obj_name})
  273. success = 'data' in response
  274. if success:
  275. print(my_tabulate(response['data'],
  276. headers=['My', 'Buy?', 'Name', 'Size', 'Limit', 'Expires', 'No.'],
  277. tablefmt="pipe"))
  278. else:
  279. if 'error' in response:
  280. print('Order access failed with message:', response['error'])
  281. else:
  282. print('Order access failed.')
  283. def gift(username=None, obj_name=None, amount=None):
  284. if username is None:
  285. username = input('Username of recipient: ')
  286. if obj_name is None:
  287. obj_name = input('Name of object to give: ')
  288. if amount is None:
  289. amount = input('How many?: ')
  290. fake_loading_bar('Sending Gift', duration=4.2)
  291. response = client_request('gift',
  292. {"session_id": connection.session_id,
  293. "username": username,
  294. "object_name": obj_name,
  295. "amount": amount})
  296. if 'error' in response:
  297. print('Order access failed with message:', response['error'])
  298. elif 'message' in response:
  299. print(response['message'])
  300. def news():
  301. fake_loading_bar('Loading Data', duration=0.76)
  302. response = client_request('news', {})
  303. success = 'data' in response
  304. if success:
  305. print(my_tabulate(response['data'],
  306. headers=['Date', 'Title'],
  307. tablefmt="pipe"))
  308. else:
  309. if 'error' in response:
  310. print('News access failed with message:', response['error'])
  311. else:
  312. print('News access failed.')
  313. def tradables():
  314. fake_loading_bar('Loading Data', duration=12.4)
  315. response = client_request('tradables', {})
  316. success = 'data' in response
  317. if success:
  318. print(my_tabulate(response['data'],
  319. headers=['Name', 'Course', 'Market Cap.'],
  320. tablefmt="pipe"))
  321. world_wealth = 0
  322. for row in response['data']:
  323. if row[2] is not None:
  324. world_wealth += row[2]
  325. print('Estimated worldwide wealth:', world_wealth)
  326. else:
  327. if 'error' in response:
  328. print('Data access failed with message:', response['error'])
  329. else:
  330. print('Data access failed.')
  331. def trades_on(obj_name=None, limit=5):
  332. limit = float(limit)
  333. if obj_name is None: # TODO list some available objects
  334. obj_name = input('Name of object to check: ')
  335. fake_loading_bar('Loading Data', duration=0.34 * limit)
  336. response = client_request('trades_on', {"session_id": connection.session_id,
  337. "ownable": obj_name,
  338. "limit": limit})
  339. success = 'data' in response
  340. if success:
  341. print(my_tabulate(response['data'],
  342. headers=['Time', 'Volume', 'Price'],
  343. tablefmt="pipe"))
  344. else:
  345. if 'error' in response:
  346. print('Trades access failed with message:', response['error'])
  347. else:
  348. print('Trades access failed.')
  349. def trades(limit=10):
  350. limit = float(limit)
  351. fake_loading_bar('Loading Data', duration=limit * 0.21)
  352. response = client_request('trades', {"session_id": connection.session_id,
  353. "limit": limit})
  354. success = 'data' in response
  355. if success:
  356. print(my_tabulate(response['data'],
  357. headers=['Buy?', 'Name', 'Volume', 'Price', 'Time'],
  358. tablefmt="pipe"))
  359. else:
  360. if 'error' in response:
  361. print('Trades access failed with message:', response['error'])
  362. else:
  363. print('Trades access failed.')
  364. def old_orders(include_canceled=None, include_executed=None, limit=10):
  365. limit = float(limit)
  366. if include_canceled is None:
  367. include_canceled = yn_dialog('Include canceled/expired orders in list?')
  368. if include_executed is None:
  369. include_executed = yn_dialog('Include fully executed orders in list?')
  370. fake_loading_bar('Loading Data', duration=limit * 0.27)
  371. response = client_request('old_orders', {"session_id": connection.session_id,
  372. "include_canceled": include_canceled,
  373. "include_executed": include_executed,
  374. "limit": limit})
  375. success = 'data' in response
  376. if success:
  377. print(my_tabulate(response['data'],
  378. headers=['Buy?', 'Name', 'Size', 'Limit', 'Expiry', 'No.', 'Status'],
  379. tablefmt="pipe"))
  380. else:
  381. if 'error' in response:
  382. print('Order access failed with message:', response['error'])
  383. else:
  384. print('Order access failed.')
  385. # noinspection PyShadowingBuiltins
  386. def exit():
  387. global exiting
  388. exiting = True