Fixed missing trades, updated coins

api-breakage
Morty Space 5 years ago
parent c63091c683
commit cf2cf98051
  1. 1
      README.md
  2. 2
      src/cryptocom/exchange/__init__.py
  3. 2
      src/cryptocom/exchange/api.py
  4. 2
      src/cryptocom/exchange/coins.py
  5. 4
      src/cryptocom/exchange/pairs.py
  6. 22
      src/cryptocom/exchange/private.py
  7. 84
      src/cryptocom/exchange/structs.py
  8. 1
      tests/test_market.py
  9. 7
      tests/test_private.py

@ -28,6 +28,7 @@ Exchange original API docs: [https://exchange-docs.crypto.com](https://exchange-
### Changelog
- **0.7.3** - fixed price of order if not filled, updated coins, added missing trades to `Order`
- **0.7.2** - fixed `listen_orders` private account method, added test
- **0.7.1** - fixed missing '.0' in order price and quantity (different in py3.7, py3.9)
- **0.7** - major changes, `Pair` -> `cro.pairs.CRO_USDT` moved to more complex structure so we can use round and server information about pairs.

@ -14,4 +14,4 @@ __all__ = [
'ApiError', 'ApiProvider'
]
__version__ = '0.7.2'
__version__ = '0.7.3'

@ -140,7 +140,7 @@ class ApiProvider:
try:
async for data in self.listen_once(url, *channels, sign=sign):
yield data
except:
except Exception:
await asyncio.sleep(1)
async def listen_once(self, url, *channels, sign=False):

@ -37,6 +37,8 @@ EGLD = Coin("EGLD")
USDC = Coin("USDC")
ADA = Coin("ADA")
ICX = Coin("ICX")
DOT = Coin("DOT")
REN = Coin("REN")
def all():

@ -83,6 +83,10 @@ EGLD_USDT = Pair("EGLD_USDT", 4, 3)
WBTC_USDT = Pair("WBTC_USDT", 2, 6)
QTUM_USDT = Pair("QTUM_USDT", 4, 4)
BAND_USDT = Pair("BAND_USDT", 4, 2)
REN_CRO = Pair("REN_CRO", 4, 2)
DOT_USDT = Pair("DOT_USDT", 4, 3)
REN_USDT = Pair("REN_USDT", 5, 2)
DOT_CRO = Pair("DOT_CRO", 3, 3)
def all():

@ -185,12 +185,24 @@ class Account:
async def get_order(self, order_id: int) -> Order:
"""Get order info."""
data = await self.api.post('private/get-order-detail', {
'params': {'order_id': str(order_id)}
})
order_info = data['order_info']
order_info = {}
retries = 0
while True:
data = await self.api.post('private/get-order-detail', {
'params': {'order_id': str(order_id)}
})
order_info = data.get('order_info', {})
if not order_info and retries < 10:
await asyncio.sleep(0.5)
retries += 1
else:
break
return Order.create_from_api(
self.pairs[order_info['instrument_name']], order_info)
self.pairs[order_info['instrument_name']],
order_info, data['trade_list']
)
async def cancel_order(
self, order_id: int, pair: Pair, check_status=False) -> None:

@ -203,6 +203,41 @@ class OrderForceType(str, Enum):
IMMEDIATE_OR_CANCEL = 'IMMEDIATE_OR_CANCEL'
@dataclass
class PrivateTrade:
id: int
side: OrderSide
pair: Pair
fees: float
fees_coin: Coin
created_at: int
filled_price: float
filled_quantity: float
order_id: int
@cached_property
def is_buy(self):
return self.side == OrderSide.BUY
@cached_property
def is_sell(self):
return self.side == OrderSide.SELL
@classmethod
def create_from_api(cls, pair: Pair, data: Dict) -> 'PrivateTrade':
return cls(
id=int(data['trade_id']),
side=OrderSide(data['side']),
pair=pair,
fees=round_up(data['fee'], 4),
fees_coin=Coin(data['fee_currency']),
created_at=int(data['create_time'] / 1000),
filled_price=pair.round_price(data['traded_price']),
filled_quantity=pair.round_quantity(data['traded_quantity']),
order_id=int(data['order_id'])
)
@dataclass
class Order:
id: int
@ -220,6 +255,7 @@ class Order:
fees_coin: Coin
force_type: OrderForceType
trigger_price: float
trades: List[PrivateTrade]
@cached_property
def is_buy(self):
@ -270,18 +306,24 @@ class Order:
return self.quantity - self.filled_quantity
@classmethod
def create_from_api(cls, pair: Pair, data: dict) -> 'Order':
def create_from_api(
cls, pair: Pair, data: Dict, trades: List[Dict] = None) -> 'Order':
fees_coin, trigger_price = None, None
if data['fee_currency']:
fees_coin = Coin(data['fee_currency'])
if data.get('trigger_price') is not None:
trigger_price = pair.round_price(data['trigger_price'])
trades = [
PrivateTrade.create_from_api(pair, trade)
for trade in trades or []
]
return cls(
id=int(data['order_id']),
status=OrderStatus(data['status']),
side=OrderSide(data['side']),
price=pair.round_price(data['price']),
price=pair.round_price(data['avg_price'] or data['price']),
quantity=pair.round_quantity(data['quantity']),
client_id=data['client_oid'],
created_at=int(data['create_time'] / 1000),
@ -292,40 +334,6 @@ class Order:
filled_quantity=pair.round_quantity(data['cumulative_quantity']),
fees_coin=fees_coin,
force_type=OrderForceType(data['time_in_force']),
trigger_price=trigger_price
)
@dataclass
class PrivateTrade:
id: int
side: OrderSide
pair: Pair
fees: float
fees_coin: Coin
created_at: int
filled_price: float
filled_quantity: float
order_id: int
@cached_property
def is_buy(self):
return self.side == OrderSide.BUY
@cached_property
def is_sell(self):
return self.side == OrderSide.SELL
@classmethod
def create_from_api(cls, pair: Pair, data: Dict) -> 'PrivateTrade':
return cls(
id=int(data['trade_id']),
side=OrderSide(data['side']),
pair=pair,
fees=round_up(data['fee'], 4),
fees_coin=Coin(data['fee_currency']),
created_at=int(data['create_time'] / 1000),
filled_price=pair.round_price(data['traded_price']),
filled_quantity=pair.round_quantity(data['traded_quantity']),
order_id=int(data['order_id'])
trigger_price=trigger_price,
trades=trades
)

@ -6,6 +6,7 @@ import cryptocom.exchange as cro
@pytest.mark.asyncio
async def test_get_pairs(exchange: cro.Exchange):
pairs = await exchange.get_pairs()
assert sorted(exchange.pairs.keys()) == sorted(p.name for p in pairs)
local_pairs = sorted(cro.pairs.all(), key=lambda p: p.name)
server_pairs = sorted(pairs, key=lambda p: p.name)
assert len(local_pairs) == len(server_pairs)

@ -121,6 +121,13 @@ async def test_account_market_orders(
])
await asyncio.sleep(1)
orders = await asyncio.gather(*[
account.get_order(order_id)
for order_id in order_ids['buy'] + order_ids['sell']
])
for order in orders:
assert order.trades, order
trades = await account.get_trades(cro.pairs.CRO_USDT, page_size=20)
for trade in trades:
if trade.is_buy:

Loading…
Cancel
Save