Skip to content

Commit

Permalink
[exchange] Allow to obtain the order ID right on order creation with …
Browse files Browse the repository at this point in the history
…'returnID=True' flag
  • Loading branch information
xeroc committed Jun 10, 2016
1 parent f550a9b commit 13852fe
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 17 deletions.
35 changes: 35 additions & 0 deletions grapheneexchange/deep_eq.py
@@ -0,0 +1,35 @@
def deep_eq(_v1, _v2):
import operator
import types

def _deep_dict_eq(d1, d2):
k1 = sorted(d1.keys())
k2 = sorted(d2.keys())
if k1 != k2: # keys should be exactly equal
return False
return sum(deep_eq(d1[k], d2[k]) for k in k1) == len(k1)

def _deep_iter_eq(l1, l2):
if len(l1) != len(l2):
return False
return sum(deep_eq(v1, v2) for v1, v2 in zip(l1, l2)) == len(l1)

op = operator.eq
c1, c2 = (_v1, _v2)

# guard against strings because they are also iterable
# and will consistently cause a RuntimeError (maximum recursion limit reached)
if isinstance(_v1, str):
return op(c1, c2)

if isinstance(_v1, dict):
op = _deep_dict_eq
else:
try:
c1, c2 = (list(iter(_v1)), list(iter(_v2)))
except TypeError:
c1, c2 = _v1, _v2
else:
op = _deep_iter_eq

return op(c1, c2)
71 changes: 54 additions & 17 deletions grapheneexchange/exchange.py
@@ -1,11 +1,12 @@
from grapheneapi.grapheneclient import GrapheneClient
from graphenebase import transactions
from graphenebase import transactions, operations
from graphenebase.account import PrivateKey
from datetime import datetime
import time
import math
from grapheneextra.proposal import Proposal
import logging
from . import deep_eq
log = logging.getLogger("graphenebase.signedtransactions")


Expand Down Expand Up @@ -163,7 +164,7 @@ def __init__(self, config, **kwargs) :
if "prefix" in kwargs:
self.prefix = kwargs["prefix"]
else:
self.prefix = "BTS"
self.prefix = getattr(config, "prefix", "BTS")

#: The wif key can be used for creating transactions **if** not
# connected to a cli_wallet
Expand Down Expand Up @@ -824,7 +825,13 @@ def returnTradeHistory(self, currencyPair="all", limit=25):
r.update({market : trades})
return r

def buy(self, currencyPair, rate, amount, expiration=7 * 24 * 60 * 60, killfill=False):
def buy(self,
currencyPair,
rate,
amount,
expiration=7 * 24 * 60 * 60,
killfill=False,
returnID=False):
""" Places a buy order in a given market (buy ``quote``, sell
``base`` in market ``quote_base``). Required POST parameters
are "currencyPair", "rate", and "amount". If successful, the
Expand All @@ -835,6 +842,7 @@ def buy(self, currencyPair, rate, amount, expiration=7 * 24 * 60 * 60, killfill=
:param number amount: Amount of ``quote`` to buy
:param number expiration: (optional) expiration time of the order in seconds (defaults to 7 days)
:param bool killfill: flag that indicates if the order shall be killed if it is not filled (defaults to False)
:param bool returnID: If this flag is True, the call will wait for the order to be included in a block and return it's id
Prices/Rates are denoted in 'base', i.e. the USD_BTS market
is priced in BTS per USD.
Expand Down Expand Up @@ -877,7 +885,8 @@ def buy(self, currencyPair, rate, amount, expiration=7 * 24 * 60 * 60, killfill=
"expiration": transactions.formatTimeFromNow(expiration),
"fill_or_kill": killfill,
}
ops = [transactions.Operation(transactions.Limit_order_create(**s))]
order = transactions.Limit_order_create(**s)
ops = [transactions.Operation(order)]
expiration = transactions.formatTimeFromNow(30)
ops = transactions.addRequiredFees(self.ws, ops, "1.3.0")
ref_block_num, ref_block_prefix = transactions.getBlockParams(self.ws)
Expand All @@ -888,19 +897,28 @@ def buy(self, currencyPair, rate, amount, expiration=7 * 24 * 60 * 60, killfill=
operations=ops
)
transaction = transaction.sign([self.config.wif], self.prefix)
transaction = transactions.JsonObj(transaction)
transaction = transactions.JsonObj(transaction)
if not (self.safe_mode or self.propose_only):
self.ws.broadcast_transaction(transaction, api="network_broadcast")
else:
raise NoWalletException()

if self.propose_only:
[self.propose_operations.append(o) for o in transaction["operations"]]
return self.propose_operations
if returnID:
return self._waitForOperationsConfirmation(transactions.JsonObj(order))
else:
return transaction

def sell(self, currencyPair, rate, amount, expiration=7 * 24 * 60 * 60, killfill=False):
if self.propose_only:
[self.propose_operations.append(o) for o in transaction["operations"]]
return self.propose_operations
else:
return transaction

def sell(self,
currencyPair,
rate,
amount,
expiration=7 * 24 * 60 * 60,
killfill=False,
returnID=False):
""" Places a sell order in a given market (sell ``quote``, buy
``base`` in market ``quote_base``). Required POST parameters
are "currencyPair", "rate", and "amount". If successful, the
Expand All @@ -911,6 +929,7 @@ def sell(self, currencyPair, rate, amount, expiration=7 * 24 * 60 * 60, killfill
:param number amount: Amount of ``quote`` to sell
:param number expiration: (optional) expiration time of the order in seconds (defaults to 7 days)
:param bool killfill: flag that indicates if the order shall be killed if it is not filled (defaults to False)
:param bool returnID: If this flag is True, the call will wait for the order to be included in a block and return it's id
Prices/Rates are denoted in 'base', i.e. the USD_BTS market
is priced in BTS per USD.
Expand Down Expand Up @@ -953,7 +972,8 @@ def sell(self, currencyPair, rate, amount, expiration=7 * 24 * 60 * 60, killfill
"expiration": transactions.formatTimeFromNow(expiration),
"fill_or_kill": killfill,
}
ops = [transactions.Operation(transactions.Limit_order_create(**s))]
order = transactions.Limit_order_create(**s)
ops = [transactions.Operation(order)]
expiration = transactions.formatTimeFromNow(30)
ops = transactions.addRequiredFees(self.ws, ops, "1.3.0")
ref_block_num, ref_block_prefix = transactions.getBlockParams(self.ws)
Expand All @@ -964,17 +984,34 @@ def sell(self, currencyPair, rate, amount, expiration=7 * 24 * 60 * 60, killfill
operations=ops
)
transaction = transaction.sign([self.config.wif], self.prefix)
transaction = transactions.JsonObj(transaction)
transaction = transactions.JsonObj(transaction)
if not (self.safe_mode or self.propose_only):
self.ws.broadcast_transaction(transaction, api="network_broadcast")
else:
raise NoWalletException()

if self.propose_only:
[self.propose_operations.append(o) for o in transaction["operations"]]
return self.propose_operations
if returnID:
return self._waitForOperationsConfirmation(transactions.JsonObj(order))
else:
return transaction
if self.propose_only:
[self.propose_operations.append(o) for o in transaction["operations"]]
return self.propose_operations
else:
return transaction

def _waitForOperationsConfirmation(self, thisop):
if self.safe_mode:
return "Safe Mode enabled, can't obtain an orderid"
counter = -2
blocknum = int(self.ws.get_dynamic_global_properties()["head_block_number"])
for block in self.ws.block_stream(start=blocknum - 2, mode="head"):
counter += 1
for tx in block["transactions"]:
for i, op in enumerate(tx["operations"]):
if deep_eq.deep_eq(op[1], thisop):
return (tx["operation_results"][i][1])
if counter > 10:
raise Exception("The operation has not been added after 10 blocks!")

def list_debt_positions(self):
""" List Call Positions (borrowed assets and amounts)
Expand Down

0 comments on commit 13852fe

Please sign in to comment.