client_controller.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  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
  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_message' in response:
  30. print('Login failed with message:', response['error_message'])
  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_message' in response:
  66. print('Registration failed with message:', response['error_message'])
  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_message' in response:
  73. print('Order cancelling failed with message:', response['error_message'])
  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_message' in response:
  99. print('Changing password failed with message:', response['error_message'])
  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. print('This corresponds to a wealth of roughly', response['own_wealth'])
  136. else:
  137. if 'error_message' in response:
  138. print('Depot access failed with message:', response['error_message'])
  139. else:
  140. print('Depot access failed.')
  141. def leaderboard():
  142. fake_loading_bar('Loading data', duration=1.3)
  143. response = client_request('leaderboard', {})
  144. success = 'data' in response
  145. if success:
  146. print(my_tabulate(response['data'], headers=['Trader', 'Wealth'], tablefmt="pipe"))
  147. # print('Remember that the goal is to be as rich as possible, not to be richer than other traders!')
  148. else:
  149. if 'error_message' in response:
  150. print('Leaderboard access failed with message:', response['error_message'])
  151. else:
  152. print('Leaderboard access failed.')
  153. def activate_key(key=''):
  154. if key == '':
  155. print('Entering a game key may get you some money or other useful stuff.')
  156. key = input('Key: ')
  157. if key == '':
  158. print('Invalid key.')
  159. fake_loading_bar('Validating Key', duration=0.4)
  160. response = client_request('activate_key', {"session_id": connection.session_id, 'key': key})
  161. if 'error_message' in response:
  162. print('Key activation failed with message:', response['error_message'])
  163. def buy(obj_name=None, amount=None, limit='', stop_loss='', expiry=None):
  164. if obj_name is None: # TODO list some available objects
  165. obj_name = input('Name of object to buy: ')
  166. if amount is None:
  167. amount = input('Amount: ')
  168. if limit == '':
  169. set_limit = yn_dialog('Do you want to place a limit?')
  170. if set_limit:
  171. limit = input('Limit: ')
  172. stop_loss = yn_dialog('Is this a stop-loss limit?')
  173. else:
  174. limit = None
  175. stop_loss = None
  176. if limit != '' and stop_loss == '':
  177. stop_loss = yn_dialog('Is this a stop-loss limit?')
  178. if limit is not None and \
  179. float(limit) <= 0 and \
  180. input(input('Are you sure you want to use such a low limit (limit=' + str(
  181. limit) + ')? (type in "yes" or something else):') != 'yes'):
  182. print('Order was not placed.')
  183. return
  184. if expiry is None:
  185. expiry = input('Time until order expires (minutes, default ' + str(DEFAULT_ORDER_EXPIRY) + '):')
  186. if expiry == '':
  187. expiry = DEFAULT_ORDER_EXPIRY
  188. try:
  189. expiry = float(expiry)
  190. except ValueError:
  191. print('Invalid expiration time.')
  192. return
  193. fake_loading_bar('Sending Data', duration=1.3)
  194. response = client_request('order', {"buy": True,
  195. "session_id": connection.session_id,
  196. "amount": amount,
  197. "ownable": obj_name,
  198. "limit": limit,
  199. "stop_loss": stop_loss,
  200. "time_until_expiration": expiry})
  201. if 'error_message' in response:
  202. print('Order placement failed with message:', response['error_message'])
  203. else:
  204. print('You might want to use the `trades` or `depot` commands',
  205. 'to see if the order has been executed already.')
  206. def sell(obj_name=None, amount=None, limit='', stop_loss='', expiry=None):
  207. if obj_name is None: # TODO list some available objects
  208. obj_name = input('Name of object to sell: ')
  209. if amount is None:
  210. amount = input('Amount: ')
  211. if limit == '':
  212. set_limit = yn_dialog('Do you want to place a limit?')
  213. if set_limit:
  214. limit = input('Limit: ')
  215. stop_loss = yn_dialog('Is this a stop-loss limit?')
  216. else:
  217. limit = None
  218. stop_loss = None
  219. if limit != '' and stop_loss == '':
  220. stop_loss = yn_dialog('Is this a stop-loss limit?')
  221. if limit is not None and \
  222. float(limit) <= 0 and \
  223. input('Are you sure you want to use such a low limit (limit=' + str(
  224. limit) + ')? (type in "yes" or something else):') != 'yes':
  225. print('Order was not placed.')
  226. return
  227. if expiry is None:
  228. expiry = input('Time until order expires (minutes, default ' + str(DEFAULT_ORDER_EXPIRY) + '):')
  229. if expiry == '':
  230. expiry = DEFAULT_ORDER_EXPIRY
  231. try:
  232. expiry = float(expiry)
  233. except ValueError:
  234. print('Invalid expiration time.')
  235. return
  236. fake_loading_bar('Sending Data', duration=1.3)
  237. response = client_request('order', {"buy": False,
  238. "session_id": connection.session_id,
  239. "amount": amount,
  240. "ownable": obj_name,
  241. "limit": limit,
  242. "stop_loss": stop_loss,
  243. "time_until_expiration": expiry})
  244. if 'error_message' in response:
  245. print('Order placement failed with message:', response['error_message'])
  246. else:
  247. print('You might want to use the `trades` or `depot` commands',
  248. 'to see if the order has been executed already.')
  249. def orders():
  250. fake_loading_bar('Loading Data', duration=0.9)
  251. response = client_request('orders', {"session_id": connection.session_id})
  252. success = 'data' in response
  253. if success:
  254. print(my_tabulate(response['data'],
  255. headers=['Buy?', 'Name', 'Size', 'Limit', 'stop-loss', 'Expires', 'No.'],
  256. tablefmt="pipe"))
  257. else:
  258. if 'error_message' in response:
  259. print('Order access failed with message:', response['error_message'])
  260. else:
  261. print('Order access failed.')
  262. def orders_on(obj_name=None):
  263. if obj_name is None: # TODO list some available objects
  264. obj_name = input('Name of object to check: ')
  265. fake_loading_bar('Loading Data', duration=2.3)
  266. response = client_request('orders_on', {"session_id": connection.session_id, "ownable": obj_name})
  267. success = 'data' in response
  268. if success:
  269. print(my_tabulate(response['data'],
  270. headers=['My', 'Buy?', 'Name', 'Size', 'Limit', 'Expires', 'No.'],
  271. tablefmt="pipe"))
  272. else:
  273. if 'error_message' in response:
  274. print('Order access failed with message:', response['error_message'])
  275. else:
  276. print('Order access failed.')
  277. def gift(username=None, obj_name=None, amount=None):
  278. if username is None:
  279. username = input('Username of recipient: ')
  280. if obj_name is None:
  281. obj_name = input('Name of object to give: ')
  282. if amount is None:
  283. amount = input('How many?: ')
  284. fake_loading_bar('Sending Gift', duration=4.2)
  285. response = client_request('gift',
  286. {"session_id": connection.session_id,
  287. "username": username,
  288. "object_name": obj_name,
  289. "amount": amount})
  290. if 'error_message' in response:
  291. print('Order access failed with message:', response['error_message'])
  292. elif 'message' in response:
  293. print(response['message'])
  294. def news():
  295. fake_loading_bar('Loading Data', duration=0.76)
  296. response = client_request('news', {})
  297. success = 'data' in response
  298. if success:
  299. print(my_tabulate(response['data'],
  300. headers=['Date', 'Title'],
  301. tablefmt="pipe"))
  302. else:
  303. if 'error_message' in response:
  304. print('News access failed with message:', response['error_message'])
  305. else:
  306. print('News access failed.')
  307. def tradables():
  308. fake_loading_bar('Loading Data', duration=12.4)
  309. response = client_request('tradables', {})
  310. success = 'data' in response
  311. if success:
  312. print(my_tabulate(response['data'],
  313. headers=['Name', 'Course', 'Market Cap.'],
  314. tablefmt="pipe"))
  315. world_wealth = 0
  316. for row in response['data']:
  317. if row[2] is not None:
  318. world_wealth += row[2]
  319. print('Estimated worldwide wealth:', world_wealth)
  320. else:
  321. if 'error_message' in response:
  322. print('Data access failed with message:', response['error_message'])
  323. else:
  324. print('Data access failed.')
  325. def trades_on(obj_name=None, limit=5):
  326. limit = float(limit)
  327. if obj_name is None: # TODO list some available objects
  328. obj_name = input('Name of object to check: ')
  329. fake_loading_bar('Loading Data', duration=0.34*limit)
  330. response = client_request('trades_on', {"session_id": connection.session_id,
  331. "ownable": obj_name,
  332. "limit": limit})
  333. success = 'data' in response
  334. if success:
  335. print(my_tabulate(response['data'],
  336. headers=['Time', 'Volume', 'Price'],
  337. tablefmt="pipe"))
  338. else:
  339. if 'error_message' in response:
  340. print('Trades access failed with message:', response['error_message'])
  341. else:
  342. print('Trades access failed.')
  343. def trades(limit=10):
  344. limit = float(limit)
  345. fake_loading_bar('Loading Data', duration=limit*0.27)
  346. response = client_request('trades', {"session_id": connection.session_id,
  347. "limit": limit})
  348. success = 'data' in response
  349. if success:
  350. print(my_tabulate(response['data'],
  351. headers=['Buy?', 'Name', 'Volume', 'Price', 'Time'],
  352. tablefmt="pipe"))
  353. else:
  354. if 'error_message' in response:
  355. print('Trades access failed with message:', response['error_message'])
  356. else:
  357. print('Trades access failed.')
  358. def old_orders(include_canceled=None, include_executed=None, limit=10):
  359. limit = float(limit)
  360. if include_canceled is None:
  361. include_canceled = yn_dialog('Include canceled/expired orders in list?')
  362. if include_executed is None:
  363. include_executed = yn_dialog('Include fully executed orders in list?')
  364. fake_loading_bar('Loading Data', duration=limit*0.37)
  365. response = client_request('old_orders', {"session_id": connection.session_id,
  366. "include_canceled": include_canceled,
  367. "include_executed": include_executed,
  368. "limit": limit})
  369. success = 'data' in response
  370. if success:
  371. print(my_tabulate(response['data'],
  372. headers=['Buy?', 'Name', 'Size', 'Limit', 'Expiry', 'No.', 'Status'],
  373. tablefmt="pipe"))
  374. else:
  375. if 'error_message' in response:
  376. print('Order access failed with message:', response['error_message'])
  377. else:
  378. print('Order access failed.')
  379. # noinspection PyShadowingBuiltins
  380. def exit():
  381. global exiting
  382. exiting = True