Browse Source

some fixes on trades

Eren Yilmaz 6 years ago
parent
commit
12315684e5
7 changed files with 85 additions and 41 deletions
  1. 2 2
      admin_console.py
  2. 5 3
      client_controller.py
  3. 11 0
      cool_query.py
  4. 43 22
      model.py
  5. 8 1
      server.py
  6. 12 9
      server_controller.py
  7. 4 4
      util.py

+ 2 - 2
admin_console.py

@@ -22,8 +22,8 @@ def cleanup():
 
 
 if __name__ == '__main__':
-    generate_keys(count=1)
-    print(model.new_stocks(count=3))
+    generate_keys(count=2)
+    print(model.new_stocks(count=1))
     # unused_keys()
     # model.drop_old_sessions()
 

+ 5 - 3
client_controller.py

@@ -7,7 +7,7 @@ from client import allowed_commands
 from connection import client_request
 from tabulate import tabulate
 
-from util import debug, str2bool
+from util import debug
 
 
 def login(username=None, password=None):
@@ -123,7 +123,9 @@ def buy(amount=None, object_name=None, limit='', stop_loss='', time_until_expira
         if set_limit:
             limit = input('Limit: ')
             stop_loss = yn_dialog('Is this a stop-loss limit?')
-    stop_loss = str2bool(stop_loss)
+        else:
+            limit = None
+            stop_loss = None
     if time_until_expiration is None:
         time_until_expiration = input('Time until order expires (minutes, default 60):')
         if time_until_expiration == '':
@@ -224,7 +226,7 @@ def transactions(object_name=None):
     success = 'data' in response
     if success:
         print(tabulate(response['data'],
-                       # TODO headers=['Date', 'Title'],
+                       headers=['Time', 'Volume', 'Price'],
                        tablefmt="pipe"))
     else:
         if 'error_message' in response:

+ 11 - 0
cool_query.py

@@ -0,0 +1,11 @@
+import model
+
+model.connect()
+model.cursor.execute('''
+            SELECT rowid
+            FROM ownership
+            WHERE user_id = ?
+            AND ownable_id = ?
+            AND amount - ? >= ?
+            ''', (3, 2, 0, '50'))
+print(model.cursor.fetchall())

+ 43 - 22
model.py

@@ -1,9 +1,9 @@
-import datetime
 import random
 import re
 import sqlite3 as db
 import sys
 import uuid
+from datetime import timedelta, datetime
 from math import floor
 
 import db_setup
@@ -370,7 +370,7 @@ def sell_ordered_amount(user_id, ownable_id):
     #     return 0
 
     cursor.execute('''
-                SELECT SUM(orders.ordered_amount - orders.executed_amount)
+                SELECT COALESCE(SUM(orders.ordered_amount - orders.executed_amount),0)
                 FROM orders, ownership
                 WHERE ownership.rowid = orders.ownership_id
                 AND ownership.user_id = ?
@@ -384,6 +384,10 @@ def sell_ordered_amount(user_id, ownable_id):
 def user_owns_at_least(amount, user_id, ownable_id):
     connect()
 
+    if not isinstance(amount, float) and not isinstance(amount, int):
+        # comparison of float with strings does not work so well in sql
+        raise AssertionError()
+
     cursor.execute('''
                 SELECT rowid
                 FROM ownership
@@ -544,10 +548,14 @@ def execute_orders(ownable_id):
             AND (buy_order."limit" IS NULL
                 OR sell_order."limit" IS NULL
                 OR (sell_order."limit" < buy_order."limit"
-                    AND sell_order.stop_loss IS NULL
-                    AND buy_order.stop_loss IS NULL))
-            ORDER BY COALESCE(sell_order."limit", 0) ASC, 
-                     -COALESCE(buy_order."limit", 0) ASC
+                    AND NOT sell_order.stop_loss
+                    AND NOT buy_order.stop_loss))
+            ORDER BY CASE WHEN sell_order."limit" IS NULL THEN 0 ELSE 1 END ASC, 
+                     CASE WHEN buy_order."limit" IS NULL THEN 0 ELSE 1 END ASC, 
+                     buy_order."limit" DESC,
+                     sell_order."limit" ASC,
+                     buy_order.ordered_amount - buy_order.executed_amount DESC,
+                     sell_order.ordered_amount - sell_order.executed_amount DESC
             LIMIT 1
             ''', (ownable_id, ownable_id,))
 
@@ -561,22 +569,23 @@ def execute_orders(ownable_id):
 
         # TODO continue and delete order if buyer has not enough money
 
-        buy_ownership_id, _, buy_limit, _, buy_order_amount, buy_executed_amount, buy_expiry_dt, sell_ownership_id, _, sell_limit, _, sell_order_amount, sell_executed_amount, sell_expiry_dt, buyer_id, seller_id, buy_order_id, sell_order_id = matching_orders
-
-        if not isinstance(buy_limit, str) and not isinstance(buy_limit, float):
-            return AssertionError()
-        if not isinstance(sell_limit, str) and not isinstance(sell_limit, float):
-            return AssertionError()
+        buy_ownership_id, _, buy_limit, _, buy_order_amount, buy_executed_amount, buy_expiry_dt, \
+            sell_ownership_id, _, sell_limit, _, sell_order_amount, sell_executed_amount, sell_expiry_dt, \
+            buyer_id, seller_id, buy_order_id, sell_order_id \
+            = matching_orders
 
-        if buy_limit == '' and sell_limit == '':
-            raise AssertionError()
-        elif buy_limit == '':
+        if buy_limit is None and sell_limit is None:
+            raise AssertionError()  # TODO find a solution
+        elif buy_limit is None:
             price = sell_limit
-        elif sell_limit == '':
+        elif sell_limit is None:
             price = buy_limit
         else:  # both not NULL
             price = (float(sell_limit) + float(buy_limit)) / 2
 
+        if price == 0:
+            raise AssertionError()  # TODO find a solution
+
         buyer_money = user_money(buyer_id)
 
         amount = min(buy_order_amount - buy_executed_amount,
@@ -584,13 +593,13 @@ def execute_orders(ownable_id):
                      floor(buyer_money / price))
 
         buy_order_finished = (buy_order_amount - buy_executed_amount - amount <= 0) or (
-                buyer_money - amount * price < price)
+            buyer_money - amount * price < price)
         sell_order_finished = (sell_order_amount - sell_executed_amount - amount <= 0)
 
         if price < 0 or amount <= 0:
             return AssertionError()
 
-        # actually execute the order, but the bank does not send or recieve anything
+        # actually execute the order, but the bank does not send or receive anything
         if buyer_id != bank_id():  # buyer pays
             cursor.execute('''
                 UPDATE ownership 
@@ -617,6 +626,8 @@ def execute_orders(ownable_id):
                 WHERE user_id = ?
                 AND ownable_id = ?
                 ''', (amount, seller_id, currency_id()))
+
+        # update order execution state
         cursor.execute('''
             UPDATE orders 
             SET executed_amount = executed_amount + ?
@@ -640,9 +651,10 @@ def execute_orders(ownable_id):
         if buyer_id != seller_id:
             cursor.execute('''
                 UPDATE orders
-                SET stop_loss = NULL
+                SET stop_loss = NULL,
                     "limit" = NULL
-                WHERE stop_loss
+                WHERE stop_loss IS NOT NULL
+                AND stop_loss
                 AND (buy AND "limit" > ?)
                     OR (NOT buy AND "limit" < ?)
                 ''', (price, price,))
@@ -688,10 +700,19 @@ def bank_order(buy, ownable_id, limit, amount, time_until_expiration):
         ''', ('External investors are selling ' + ownable_name + ' atm',))
 
 
-def place_order(buy, ownership_id, limit, stop_loss, amount, time_until_expiration):
+def current_time():  # might differ from datetime.datetime.now() for time zone reasons
     connect()
 
-    expiry = datetime.datetime.now() + datetime.timedelta(minutes=time_until_expiration)
+    cursor.execute('''
+        SELECT datetime('now')
+        ''')
+
+    return cursor.fetchone()[0]
+
+
+def place_order(buy, ownership_id, limit, stop_loss, amount, time_until_expiration):
+    connect()
+    expiry = datetime.strptime(current_time(), '%Y-%m-%d %H:%M:%S') + timedelta(minutes=time_until_expiration)
 
     cursor.execute('''
                 INSERT INTO orders 

+ 8 - 1
server.py

@@ -13,7 +13,14 @@ if __name__ == '__main__':
 
     model.setup()
 
-    valid_routes = ['login', 'register', 'depot', 'activate_key', 'order', 'orders', 'news', 'transactions', 'orders_on']
+    valid_routes = ['login',
+                    'register',
+                    'depot',
+                    'activate_key',
+                    'order', 'orders',
+                    'news',
+                    'transactions',
+                    'orders_on']
 
 
     @route('/<path>', method='POST')

+ 12 - 9
server_controller.py

@@ -3,12 +3,12 @@ import json
 from bottle import request, response
 
 import model
-from util import debug, str2bool
+from util import debug
 
 
 def missing_attributes(attributes):
     for attr in attributes:
-        if attr not in request.json:
+        if attr not in request.json or request.json[attr] == '':
             if str(attr) == 'session_id':
                 return 'You are not signed in.'
             return 'Missing value for attribute ' + str(attr)
@@ -81,6 +81,7 @@ def order():
     sell = not buy
     session_id = request.json['session_id']
     amount = request.json['amount']
+    amount = float(amount)
     ownable_name = request.json['ownable']
     time_until_expiration = float(request.json['time_until_expiration'])
     if time_until_expiration < 0:
@@ -93,6 +94,8 @@ def order():
     try:
         if request.json['limit'] == '':
             limit = None
+        elif request.json['limit'] is None:
+            limit = None
         else:
             limit = float(request.json['limit'])
     except ValueError:  # for example when float fails
@@ -103,19 +106,19 @@ def order():
     try:
         if request.json['stop_loss'] == '':
             stop_loss = None
+        elif request.json['stop_loss'] is None:
+            stop_loss = None
         else:
-            stop_loss = 'stop_loss' in request.json and str2bool(request.json['stop_loss'])
+            stop_loss = 'stop_loss' in request.json and request.json['stop_loss']
         if stop_loss is not None and limit is None:
             return bad_request('Can only set stop loss for limit orders')
-    except ValueError:  # for example when bool fails
-        return bad_request('Invalid value for stop loss')
     except KeyError:  # for example when stop_loss was not specified
-        limit = None
+        stop_loss = None
 
     # TODO test if stop loss works
 
     if sell:
-        if not model.user_owns_at_least(user_id, amount, ownership_id):
+        if not model.user_owns_at_least(amount, user_id, ownable_id):
             return bad_request('You can not sell more than you own.')
 
     model.place_order(buy, ownership_id, limit, stop_loss, amount, time_until_expiration)
@@ -167,7 +170,7 @@ def not_found(msg=''):
 def forbidden(msg=''):
     response.status = 403
     if debug:
-        msg = str(response.status) + ' Forbidden: ' + msg
+        msg = str(response.status) + ': ' + msg
     response.content_type = 'application/json'
     return json.dumps({"error_message": msg})
 
@@ -175,6 +178,6 @@ def forbidden(msg=''):
 def bad_request(msg=''):
     response.status = 400
     if debug:
-        msg = str(response.status) + ' Bad request: ' + msg
+        msg = str(response.status) + ': ' + msg
     response.content_type = 'application/json'
     return json.dumps({"error_message": msg})

+ 4 - 4
util.py

@@ -4,9 +4,9 @@ import numpy
 debug = True
 chars = [str(d) for d in range(1, 10)]
 
-p = [1 for _ in chars]
-with open('letter_dist.csv', newline='') as csvfile:
-    reader = csv.reader(csvfile, delimiter=',')
+p = [1. for _ in chars]
+with open('letter_dist.csv', newline='') as csv_file:
+    reader = csv.reader(csv_file, delimiter=',')
     sp = sum(p)
     for row in reader:
         chars.append(row[0])
@@ -19,7 +19,7 @@ def random_chars(count):
 
 
 def str2bool(v):
-    v = v.strip().lower()
+    v = str(v).strip().lower()
     if v in ["yes", 'y' "true", "t", "1"]:
         return True
     if v in ["no", 'n' "false", "f", "0", '', 'null', 'none']: