trading_bot.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import random
  2. from datetime import timedelta, datetime
  3. from math import log2, ceil
  4. import model
  5. from debug import debug
  6. from game import DEFAULT_ORDER_EXPIRY
  7. def place_order(ownable_id):
  8. """
  9. places a new order according to the algorithm described in `assets/follower.py`
  10. :param ownable_id: on which ownable to place the order
  11. :return: True iff a new order was placed
  12. """
  13. best_buy_order, cheapest_sell_order = model.abs_spread(ownable_id)
  14. if best_buy_order is None or cheapest_sell_order is None:
  15. return False
  16. investors_id = model.bank_id()
  17. orders = model.get_ownable_orders(investors_id, ownable_id)
  18. orders = [random.choice(orders) for _ in range(int(ceil(log2(len(orders)))))]
  19. amounts = [order[3] for order in orders]
  20. amount = ceil(sum(amounts) / len(amounts))
  21. expiry = datetime.strptime(model.current_db_time(), '%Y-%m-%d %H:%M:%S') + timedelta(minutes=DEFAULT_ORDER_EXPIRY)
  22. limit = random.uniform(best_buy_order, cheapest_sell_order)
  23. if limit - best_buy_order < cheapest_sell_order - limit:
  24. model.place_order(buy=True,
  25. ownership_id=model.get_ownership_id(ownable_id, investors_id),
  26. limit=limit,
  27. stop_loss=False,
  28. amount=amount,
  29. expiry=expiry)
  30. else:
  31. model.place_order(buy=False,
  32. ownership_id=model.get_ownership_id(ownable_id, investors_id),
  33. limit=limit,
  34. stop_loss=False,
  35. amount=amount,
  36. expiry=expiry)
  37. return True
  38. def main(): # TODO testen
  39. """the initial part of the trading bot algorithm"""
  40. if model.get_user_orders(model.bank_id()):
  41. raise AssertionError('The trading bot already has some orders.')
  42. if input('Are you sure you want to place the initial orders? (type in "yes" or something else):') == 'yes':
  43. for ownable_id in model.ownable_ids():
  44. if ownable_id != model.currency_id():
  45. place_order(ownable_id)
  46. else:
  47. print('Not placing orders.')
  48. model.cleanup()
  49. if __name__ == '__main__':
  50. main()
  51. def notify_expired_orders(orders):
  52. for order in orders:
  53. # order_id = order[0]
  54. ownership_id = order[1]
  55. # check if that was one of the bots orders
  56. bank_ownership_id = model.get_ownership_id(ownership_id, model.bank_id())
  57. if ownership_id != bank_ownership_id:
  58. continue
  59. # create a new order
  60. ownable_id = model.ownable_id_by_ownership_id(ownership_id)
  61. place_order(ownable_id)
  62. def notify_order_traded(ownable_id):
  63. """
  64. Called after a trade has been done and now the auctions are finished.
  65. :param ownable_id: the ownable that was traded
  66. :return: True iff a new order was placed
  67. """
  68. model.connect()
  69. if ownable_id == model.currency_id():
  70. return False
  71. ownership_id = model.get_ownership_id(ownable_id, model.bank_id())
  72. if debug: # the bot should only have one order
  73. model.cursor.execute('''
  74. SELECT COUNT(*) <= 1
  75. FROM orders
  76. WHERE ownership_id = ?
  77. ''', (ownership_id,))
  78. if not model.cursor.fetchone()[0]:
  79. raise AssertionError('The bot should have at most one order.')
  80. model.cursor.execute('''
  81. SELECT rowid, ordered_amount, expiry_dt
  82. FROM orders
  83. WHERE ownership_id = ?
  84. -- no need for ORDER since the bot should have only one order
  85. UNION ALL
  86. SELECT * FROM (
  87. SELECT NULL, ordered_amount, expiry_dt
  88. FROM order_history
  89. ORDER BY rowid DESC -- equivalent to ordering by time created
  90. )
  91. LIMIT 1
  92. ''', (ownership_id,))
  93. data = model.cursor.fetchall()
  94. if not data:
  95. return place_order(ownable_id)
  96. my_last_order = data[0]
  97. last_order_open = my_last_order[0] is None
  98. last_order_id = my_last_order[0]
  99. last_amount = my_last_order[1]
  100. expiry = my_last_order[2]
  101. dt_order_placed = datetime.strptime(expiry, '%Y-%m-%d %H:%M:%S') - timedelta(minutes=DEFAULT_ORDER_EXPIRY)
  102. model.cursor.execute('''
  103. SELECT 2 * SUM(amount) >= ?
  104. FROM transactions
  105. WHERE ownable_id = ?
  106. AND dt >= ?
  107. ''', (last_amount, ownable_id, dt_order_placed))
  108. if model.cursor.fetchone()[0]:
  109. if last_order_open:
  110. model.delete_order(last_order_id, 'Canceled')
  111. return place_order(ownable_id)
  112. return False