def test_post_sequentially(self): post1 = { "uid": "foo", "count": 2, "type": "Trade", "username": "******", "contract": "MXN", "quantity": 5, "direction": "debit", "note": "test_debit", "timestamp": util.dt_to_timestamp(datetime.datetime.utcnow()), } post2 = { "uid": "foo", "count": 2, "type": "Trade", "username": "******", "contract": "MXN", "quantity": 5, "direction": "credit", "note": "test_credit", "timestamp": util.dt_to_timestamp(datetime.datetime.utcnow()), } d1 = self.export.post(post1) return self.export.post(post2)
def test_post_results_agree(self): post1 = { "uid": "foo", "count": 2, "type": "Trade", "username": "******", "contract": "MXN", "quantity": 5, "direction": "debit", "note": "debit", "timestamp": util.dt_to_timestamp(datetime.datetime.utcnow()), } post2 = { "uid": "foo", "count": 2, "type": "Trade", "username": "******", "contract": "MXN", "quantity": 5, "direction": "credit", "note": "credit", "timestamp": util.dt_to_timestamp(datetime.datetime.utcnow()), } d1 = self.export.post(post1) d2 = self.export.post(post2) return self.assertEqual(self.successResultOf(d1), self.successResultOf(d2))
def test_quantity_mismatch(self): post1 = { "uid": "foo", "count": 2, "type": "Trade", "username": "******", "contract": "MXN", "quantity": 5, "direction": "debit", "note": "debit", "timestamp": util.dt_to_timestamp(datetime.datetime.utcnow()), } post2 = { "uid": "foo", "count": 2, "type": "Trade", "username": "******", "contract": "MXN", "quantity": 1, "direction": "credit", "note": "credit", "timestamp": util.dt_to_timestamp(datetime.datetime.utcnow()), } d1 = self.export.post(post1) d1.addErrback(lambda x: None) d2 = self.assertFailure(self.export.post(post2), LedgerException) self.flushLoggedErrors() return self.assertEqual(self.successResultOf(d2), ledger.QUANTITY_MISMATCH)
def test_post_results_agree(self): post1 = { "uid": "foo", "count": 2, "type": "Trade", "username": "******", "contract": "MXN", "quantity": 5, "direction": "debit", "note": 'debit', "timestamp": util.dt_to_timestamp(datetime.datetime.utcnow()) } post2 = { "uid": "foo", "count": 2, "type": "Trade", "username": "******", "contract": "MXN", "quantity": 5, "direction": "credit", "note": "credit", "timestamp": util.dt_to_timestamp(datetime.datetime.utcnow()) } d1 = self.export.post(post1) d2 = self.export.post(post2) return self.assertEqual(self.successResultOf(d1), self.successResultOf(d2))
def test_post_sequentially(self): post1 = { "uid": "foo", "count": 2, "type": "Trade", "username": "******", "contract": "MXN", "quantity": 5, "direction": "debit", "note": "test_debit", "timestamp": util.dt_to_timestamp(datetime.datetime.utcnow()) } post2 = { "uid": "foo", "count": 2, "type": "Trade", "username": "******", "contract": "MXN", "quantity": 5, "direction": "credit", "note": "test_credit", "timestamp": util.dt_to_timestamp(datetime.datetime.utcnow()) } d1 = self.export.post(post1) return self.export.post(post2)
def test_quantity_mismatch(self): post1 = { "uid": "foo", "count": 2, "type": "Trade", "username": "******", "contract": "MXN", "quantity": 5, "direction": "debit", "note": 'debit', "timestamp": util.dt_to_timestamp(datetime.datetime.utcnow()) } post2 = { "uid": "foo", "count": 2, "type": "Trade", "username": "******", "contract": "MXN", "quantity": 1, "direction": "credit", "note": 'credit', "timestamp": util.dt_to_timestamp(datetime.datetime.utcnow()) } d1 = self.export.post(post1) d1.addErrback(lambda x: None) d2 = self.assertFailure(self.export.post(post2), LedgerException) self.flushLoggedErrors() return self.assertEqual(self.successResultOf(d2), ledger.QUANTITY_MISMATCH)
def load_contract(self, ticker): res = yield self.dbpool.runQuery("SELECT ticker, description, denominator, contract_type, full_description," "tick_size, lot_size, margin_high, margin_low," "denominated_contract_ticker, payout_contract_ticker, expiration " "FROM contracts WHERE ticker = %s", (ticker,)) if len(res) < 1: raise PostgresException("No such contract: %s" % ticker) if len(res) > 1: raise PostgresException("Contract %s not unique" % ticker) r = res[0] contract = {"contract": r[0], "description": r[1], "denominator": r[2], "contract_type": r[3], "full_description": markdown.markdown(r[4].decode('utf-8'), extensions=["markdown.extensions.extra", "markdown.extensions.sane_lists", "markdown.extensions.nl2br" ]), "tick_size": r[5], "lot_size": r[6], "denominated_contract_ticker": r[9], "payout_contract_ticker": r[10]} if contract['contract_type'] == 'futures': contract['margin_high'] = r[7] contract['margin_low'] = r[8] if contract['contract_type'] in ['futures', 'prediction']: contract['expiration'] = util.dt_to_timestamp(r[11]) returnValue(contract)
def authenticateWithAuthCode(self, code): self._log_call("authenticateWithAuthCode", code) expiry = datetime.utcnow() + timedelta(days=1) from sputnik import util return defer.succeed({ 'access_token': 'TOKEN', 'expires_at': util.dt_to_timestamp(expiry) / 1e6 })
def get_transaction_history(self, start_timestamp=None, end_timestamp=None, username=None): """ :param from_timestamp: :param to_timestamp: :returns: Deferred """ if start_timestamp is None: start_timestamp = util.dt_to_timestamp(datetime.datetime.utcnow() - datetime.timedelta(days=30)) if end_timestamp is None: end_timestamp = util.dt_to_timestamp(datetime.datetime.utcnow()) history = yield self.db.get_transaction_history(start_timestamp, end_timestamp, username) returnValue(history)
def get_open_orders(self, username): results = yield self.dbpool.runQuery( 'SELECT contracts.ticker, orders.price, orders.quantity, orders.quantity_left, ' 'orders.timestamp, orders.side, orders.id FROM orders, contracts ' 'WHERE orders.contract_id=contracts.id AND orders.username=%s ' 'AND orders.quantity_left > 0 ' 'AND orders.accepted=TRUE AND orders.is_cancelled=FALSE', (username,)) returnValue({r[6]: {'contract': r[0], 'price': r[1], 'quantity': r[2], 'quantity_left': r[3], 'timestamp': util.dt_to_timestamp(r[4]), 'side': r[5], 'id': r[6], 'is_cancelled': False} for r in results})
def get_trade_history(self, contract, start_timestamp=None, end_timestamp=None): if contract not in self.markets: raise WebserverException("exceptions/webserver/no-such-ticker", contract) now = util.dt_to_timestamp(datetime.utcnow()) start = start_timestamp or int(now - 3.6e9) # delta 1 hour end = end_timestamp or now history = yield succeed([entry for entry in self.trade_history.get(contract, []) \ if start <= entry["timestamp"] <= end]) returnValue(history)
def get_transaction_history(self, start_timestamp=None, end_timestamp=None, username=None): """ :param from_timestamp: :param to_timestamp: :returns: Deferred """ if start_timestamp is None: start_timestamp = util.dt_to_timestamp(datetime.datetime.utcnow() - datetime.timedelta(days=30)) if end_timestamp is None: end_timestamp = util.dt_to_timestamp(datetime.datetime.utcnow()) history = yield self.db.get_transaction_history( start_timestamp, end_timestamp, username) returnValue(history)
def place_order(self, order, username=None): order["timestamp"] = util.dt_to_timestamp(datetime.datetime.utcnow()) order['username'] = username # Check for zero price or quantity if order["price"] == 0 or order["quantity"] == 0: raise WebserverException("exceptions/webserver/invalid_price_quantity") # check tick size and lot size in the accountant, not here result = yield self.accountant.proxy.place_order(username, order) returnValue(result)
def get_trade_history(self, contract, start_timestamp=None, end_timestamp=None): if contract not in self.markets: raise WebserverException("exceptions/webserver/no-such-ticker", contract) now = util.dt_to_timestamp(datetime.utcnow()) start = start_timestamp or int(now - 3.6e9) # delta 1 hour end = end_timestamp or now history = yield succeed( [entry for entry in self.trade_history.get(contract, []) if start <= entry["timestamp"] <= end] ) returnValue(history)
def test_database_commit(self): post1 = { "uid": "foo", "count": 2, "type": "Trade", "username": "******", "contract": "MXN", "quantity": 5, "direction": "debit", "note": "debit", "timestamp": util.dt_to_timestamp(datetime.datetime.utcnow()), } post2 = { "uid": "foo", "count": 2, "type": "Trade", "username": "******", "contract": "MXN", "quantity": 5, "direction": "credit", "note": "credit", "timestamp": util.dt_to_timestamp(datetime.datetime.utcnow()), } d = self.export.post(post1, post2) def dbtest(arg): postings = self.session.query(models.Posting).all() self.assertEqual(len(postings), 2) journals = self.session.query(models.Journal).all() self.assertEqual(len(journals), 1) p1 = postings[0] p2 = postings[1] journal = journals[0] self.assertEqual(p1.journal_id, journal.id) self.assertEqual(p2.journal_id, journal.id) self.assertEqual(abs(p1.quantity), 5) self.assertEqual(p1.quantity + p2.quantity, 0) return d.addCallback(dbtest)
def test_database_commit(self): post1 = { "uid": "foo", "count": 2, "type": "Trade", "username": "******", "contract": "MXN", "quantity": 5, "direction": "debit", "note": "debit", "timestamp": util.dt_to_timestamp(datetime.datetime.utcnow()) } post2 = { "uid": "foo", "count": 2, "type": "Trade", "username": "******", "contract": "MXN", "quantity": 5, "direction": "credit", "note": "credit", "timestamp": util.dt_to_timestamp(datetime.datetime.utcnow()) } d = self.export.post(post1, post2) def dbtest(arg): postings = self.session.query(models.Posting).all() self.assertEqual(len(postings), 2) journals = self.session.query(models.Journal).all() self.assertEqual(len(journals), 1) p1 = postings[0] p2 = postings[1] journal = journals[0] self.assertEqual(p1.journal_id, journal.id) self.assertEqual(p2.journal_id, journal.id) self.assertEqual(abs(p1.quantity), 5) self.assertEqual(p1.quantity + p2.quantity, 0) return d.addCallback(dbtest)
def place_order(self, order, username=None): order["timestamp"] = util.dt_to_timestamp(datetime.datetime.utcnow()) order['username'] = username # Check for zero price or quantity if order["price"] == 0 or order["quantity"] == 0: raise WebserverException( "exceptions/webserver/invalid_price_quantity") # check tick size and lot size in the accountant, not here result = yield self.accountant.proxy.place_order(username, order) returnValue(result)
def test_post_simultaneously(self): post1 = { "uid": "foo", "count": 2, "type": "Trade", "username": "******", "contract": "MXN", "quantity": 5, "direction": "debit", "note": 'debit', "timestamp": util.dt_to_timestamp(datetime.datetime.utcnow()) } post2 = { "uid": "foo", "count": 2, "type": "Trade", "username": "******", "contract": "MXN", "quantity": 5, "direction": "credit", "note": 'credit', "timestamp": util.dt_to_timestamp(datetime.datetime.utcnow()) } return self.export.post(post1, post2)
def get_ohlcv_history(self, contract, period=None, start_timestamp=None, end_timestamp=None): if contract not in self.markets: raise WebserverException("exceptions/webserver/no-such-ticker", contract) now = util.dt_to_timestamp(datetime.utcnow()) start = start_timestamp or int(now - 5.184e12) # delta 60 days end = end_timestamp or now period = period or "day" data = self.ohlcv_history.get(contract, {}).get(period, {}) ohlcv = yield succeed({key: value for key, value in data.iteritems() \ if value["open_timestamp"] <= end and \ start <= value["close_timestamp"]}) returnValue(ohlcv)
def get_trade_history(self, ticker): to_dt = datetime.datetime.utcnow() from_dt = to_dt - datetime.timedelta(days=60) start_dt_for_period = { 'minute': to_dt - datetime.timedelta(minutes=60), 'hour': to_dt - datetime.timedelta(hours=60), 'day': to_dt - datetime.timedelta(days=60) } results = yield self.dbpool.runQuery( "SELECT contracts.ticker, trades.timestamp, trades.price, trades.quantity FROM trades, contracts WHERE " "trades.contract_id=contracts.id AND contracts.ticker=%s AND trades.timestamp >= %s AND trades.posted IS TRUE", (ticker, from_dt)) trades = [{'contract': r[0], 'price': r[2], 'quantity': r[3], 'timestamp': util.dt_to_timestamp(r[1])} for r in results] returnValue(trades)
def get_new_api_credentials(self, expiration=None, totp=None, username=None): if expiration is None: now = datetime.utcnow() expiration = util.dt_to_timestamp(now + timedelta(days=7)) # Check totp totp_result = yield self.administrator.proxy.check_totp(username, totp) if totp_result: r = yield self.administrator.proxy.get_new_api_credentials( username, expiration) returnValue(r) else: raise WebserverException("exceptions/webserver/invalid_otp")
def load_contract(self, ticker): res = yield self.dbpool.runQuery( "SELECT ticker, description, denominator, contract_type, full_description," "tick_size, lot_size, margin_high, margin_low," "denominated_contract_ticker, payout_contract_ticker, expiration " "FROM contracts WHERE ticker = %s", (ticker, )) if len(res) < 1: raise PostgresException("No such contract: %s" % ticker) if len(res) > 1: raise PostgresException("Contract %s not unique" % ticker) r = res[0] contract = { "contract": r[0], "description": r[1], "denominator": r[2], "contract_type": r[3], "full_description": markdown.markdown(r[4].decode('utf-8'), extensions=[ "markdown.extensions.extra", "markdown.extensions.sane_lists", "markdown.extensions.nl2br" ]), "tick_size": r[5], "lot_size": r[6], "denominated_contract_ticker": r[9], "payout_contract_ticker": r[10] } if contract['contract_type'] == 'futures': contract['margin_high'] = r[7] contract['margin_low'] = r[8] if contract['contract_type'] in ['futures', 'prediction']: contract['expiration'] = util.dt_to_timestamp(r[11]) returnValue(contract)
def test_timeout(self): post1 = { "uid": "foo", "count": 2, "type": "Trade", "username": "******", "contract": "MXN", "quantity": 5, "direction": "debit", "note": 'debit', "timestamp": util.dt_to_timestamp(datetime.datetime.utcnow()) } d1 = self.assertFailure(self.export.post(post1), LedgerException) group = self.ledger.pending["foo"] group.callLater = self.clock.callLater group.setTimeout(1) self.clock.advance(2) return self.assertEqual(self.successResultOf(d1), ledger.GROUP_TIMEOUT)
def get_ohlcv_history(self, contract, period=None, start_timestamp=None, end_timestamp=None): if contract not in self.markets: raise WebserverException("exceptions/webserver/no-such-ticker", contract) now = util.dt_to_timestamp(datetime.utcnow()) start = start_timestamp or int(now - 5.184e12) # delta 60 days end = end_timestamp or now period = period or "day" data = self.ohlcv_history.get(contract, {}).get(period, {}) ohlcv = yield succeed( { key: value for key, value in data.iteritems() if value["open_timestamp"] <= end and start <= value["close_timestamp"] } ) returnValue(ohlcv)
def test_timeout(self): post1 = { "uid": "foo", "count": 2, "type": "Trade", "username": "******", "contract": "MXN", "quantity": 5, "direction": "debit", "note": "debit", "timestamp": util.dt_to_timestamp(datetime.datetime.utcnow()), } d1 = self.assertFailure(self.export.post(post1), LedgerException) group = self.ledger.pending["foo"] group.callLater = self.clock.callLater group.setTimeout(1) self.clock.advance(2) return self.assertEqual(self.successResultOf(d1), ledger.GROUP_TIMEOUT)
def get_trade_history(self, ticker): to_dt = datetime.datetime.utcnow() from_dt = to_dt - datetime.timedelta(days=60) start_dt_for_period = { 'minute': to_dt - datetime.timedelta(minutes=60), 'hour': to_dt - datetime.timedelta(hours=60), 'day': to_dt - datetime.timedelta(days=60) } results = yield self.dbpool.runQuery( "SELECT contracts.ticker, trades.timestamp, trades.price, trades.quantity FROM trades, contracts WHERE " "trades.contract_id=contracts.id AND contracts.ticker=%s AND trades.timestamp >= %s AND trades.posted IS TRUE", (ticker, from_dt)) trades = [{ 'contract': r[0], 'price': r[2], 'quantity': r[3], 'timestamp': util.dt_to_timestamp(r[1]) } for r in results] returnValue(trades)
def get_transaction_history(self, from_timestamp, to_timestamp, username): result = yield self.dbpool.runQuery( "SELECT contracts.ticker, SUM(posting.quantity) FROM posting, journal, contracts " "WHERE posting.journal_id=journal.id AND posting.username=%s AND journal.timestamp<%s " "AND posting.contract_id=contracts.id GROUP BY contracts.ticker", (username, util.timestamp_to_dt(from_timestamp))) balances = collections.defaultdict(int) for row in result: balances[row[0]] = int(row[1]) result = yield self.dbpool.runQuery( "SELECT contracts.ticker, journal.timestamp, posting.quantity, journal.type, posting.note " "FROM posting, journal, contracts WHERE posting.journal_id=journal.id AND " "posting.username=%s AND journal.timestamp>=%s AND journal.timestamp<=%s " "AND posting.contract_id=contracts.id ORDER BY journal.timestamp", (username, util.timestamp_to_dt(from_timestamp), util.timestamp_to_dt(to_timestamp))) transactions = [] for row in result: balances[row[0]] += row[2] quantity = abs(row[2]) # Here we assume that the user is a Liability user if row[2] < 0: direction = 'debit' else: direction = 'credit' transactions.append({ 'contract': row[0], 'timestamp': util.dt_to_timestamp(row[1]), 'quantity': quantity, 'type': row[3], 'direction': direction, 'balance': balances[row[0]], 'note': row[4] }) returnValue(transactions)
def get_open_orders(self, username): results = yield self.dbpool.runQuery( 'SELECT contracts.ticker, orders.price, orders.quantity, orders.quantity_left, ' 'orders.timestamp, orders.side, orders.id FROM orders, contracts ' 'WHERE orders.contract_id=contracts.id AND orders.username=%s ' 'AND orders.quantity_left > 0 ' 'AND orders.accepted=TRUE AND orders.is_cancelled=FALSE', (username, )) returnValue({ r[6]: { 'contract': r[0], 'price': r[1], 'quantity': r[2], 'quantity_left': r[3], 'timestamp': util.dt_to_timestamp(r[4]), 'side': r[5], 'id': r[6], 'is_cancelled': False } for r in results })
def get_transaction_history(self, from_timestamp, to_timestamp, username): result = yield self.dbpool.runQuery( "SELECT contracts.ticker, SUM(posting.quantity) FROM posting, journal, contracts " "WHERE posting.journal_id=journal.id AND posting.username=%s AND journal.timestamp<%s " "AND posting.contract_id=contracts.id GROUP BY contracts.ticker", (username, util.timestamp_to_dt(from_timestamp))) balances = collections.defaultdict(int) for row in result: balances[row[0]] = int(row[1]) result = yield self.dbpool.runQuery( "SELECT contracts.ticker, journal.timestamp, posting.quantity, journal.type, posting.note " "FROM posting, journal, contracts WHERE posting.journal_id=journal.id AND " "posting.username=%s AND journal.timestamp>=%s AND journal.timestamp<=%s " "AND posting.contract_id=contracts.id ORDER BY journal.timestamp", (username, util.timestamp_to_dt(from_timestamp), util.timestamp_to_dt(to_timestamp))) transactions = [] for row in result: balances[row[0]] += row[2] quantity = abs(row[2]) # Here we assume that the user is a Liability user if row[2] < 0: direction = 'debit' else: direction = 'credit' transactions.append({'contract': row[0], 'timestamp': util.dt_to_timestamp(row[1]), 'quantity': quantity, 'type': row[3], 'direction': direction, 'balance': balances[row[0]], 'note': row[4]}) returnValue(transactions)
def authenticateWithAuthCode(self, code): self._log_call("authenticateWithAuthCode", code) expiry = datetime.utcnow() + timedelta(days=1) from sputnik import util return defer.succeed({'access_token': 'TOKEN', 'expires_at': util.dt_to_timestamp(expiry)/1e6})