1
0

Compare commits

..

No commits in common. "39cee8c601260eaa78bb221f3f3d973abf039868" and "678390e881e2373f8d9c8b7acf3aafb0bfbf0884" have entirely different histories.

4 changed files with 68 additions and 128 deletions

View File

@ -6,7 +6,7 @@ from decimal import Decimal
from typing import TypeVar from typing import TypeVar
import enforce_typing import enforce_typing
from fin_defs import Asset, AssetAmount from fin_defs import Asset
@enforce_typing.enforce_types @enforce_typing.enforce_types
@ -124,36 +124,40 @@ class TradeOrderDetails:
- `raw_order_details`: For storing arbitrary unstructured data from backend. - `raw_order_details`: For storing arbitrary unstructured data from backend.
""" """
input: AssetAmount input_asset: Asset
output: AssetAmount input_amount: Decimal
fee: AssetAmount output_asset: Asset
output_amount: Decimal
fee_asset: Asset
fee_amount: Decimal
executed_time: datetime.datetime executed_time: datetime.datetime
order_id: object order_id: object
raw_order_details: object raw_order_details: object
@enforce_typing.enforce_types @enforce_typing.enforce_types
@dataclasses.dataclass(frozen=True) @dataclasses.dataclass(frozen=True)
class WithdrawalDetails: class WithdrawalDetails:
withdrawn: AssetAmount withdrawn_asset: Asset
fee: AssetAmount withdrawn_amount: Decimal
executed_time: datetime.datetime
raw_details: object
fee_asset: Asset
fee_amount: Decimal
executed_time: datetime.datetime
raw_details: object
@enforce_typing.enforce_types @enforce_typing.enforce_types
@dataclasses.dataclass(frozen=True) @dataclasses.dataclass(frozen=True)
class DepositDetails: class DepositDetails:
deposit: AssetAmount deposit_asset: Asset
fee: AssetAmount deposit_amount: Decimal
fee_asset: Asset
fee_amount: Decimal
executed_time: datetime.datetime executed_time: datetime.datetime
raw_details: object raw_details: object
@enforce_typing.enforce_types
@dataclasses.dataclass(frozen=True)
class DoubleRegister:
input: AssetAmount | None
output: AssetAmount | None
executed_time: datetime.datetime

View File

@ -3,22 +3,13 @@
import datetime import datetime
import logging import logging
import time import time
from collections.abc import Iterator
from decimal import Decimal from decimal import Decimal
import fin_defs import fin_defs
import kucoin.client import kucoin.client
from fin_defs import AssetAmount
from .data import ( from .data import (DepoFetcher, DepoGroup, DepoSingle, TradeOrderDetails,
DepoFetcher, WithdrawalDetails, DepositDetails)
DepoGroup,
DepoSingle,
DepositDetails,
DoubleRegister,
TradeOrderDetails,
WithdrawalDetails,
)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -29,36 +20,6 @@ def parse_asset_from_ticker(ticker: str) -> fin_defs.Asset:
return fin_defs.WELL_KNOWN_SYMBOLS[ticker] return fin_defs.WELL_KNOWN_SYMBOLS[ticker]
def order_from_json(order_details: dict):
(asset, base_asset) = [
parse_asset_from_ticker(a) for a in order_details['symbol'].split('-')
]
# Convert from kucoin results
if order_details['side'] == 'buy':
input_asset, output_asset = base_asset, asset
input_amount_final = Decimal(order_details['dealFunds'])
output_amount_final = Decimal(order_details['dealSize'])
else:
input_asset, output_asset = asset, base_asset
output_amount_final = Decimal(order_details['dealFunds'])
input_amount_final = Decimal(order_details['dealSize'])
fee_asset = parse_asset_from_ticker(order_details['feeCurrency'])
return TradeOrderDetails(
input=AssetAmount(input_asset, input_amount_final),
output=AssetAmount(output_asset, output_amount_final),
fee=AssetAmount(fee_asset, Decimal(order_details['fee'])),
executed_time=datetime.datetime.fromtimestamp(
order_details['createdAt'] / 1000,
tz=datetime.UTC,
),
order_id=order_details['id'],
raw_order_details=order_details,
)
class KucoinDepoFetcher(DepoFetcher): class KucoinDepoFetcher(DepoFetcher):
"""`Depo` fetcher for [Kucoin](https://www.kucoin.com), the online crypto currency exchange. """`Depo` fetcher for [Kucoin](https://www.kucoin.com), the online crypto currency exchange.
@ -184,7 +145,7 @@ class KucoinDepoFetcher(DepoFetcher):
del symbol, side, size, funds, input_amount del symbol, side, size, funds, input_amount
# Determine order details # Determine order details
return self._get_order_details(response['orderId']) return self._get_order_details(response['orderId'], input_asset, output_asset)
def _get_withdrawals(self) -> list[WithdrawalDetails]: def _get_withdrawals(self) -> list[WithdrawalDetails]:
raw_details = self.kucoin_client.get_withdrawals() raw_details = self.kucoin_client.get_withdrawals()
@ -200,19 +161,15 @@ class KucoinDepoFetcher(DepoFetcher):
tz=datetime.UTC, tz=datetime.UTC,
) )
withdrawals.append( withdrawals.append(WithdrawalDetails(withdrawn_asset,
WithdrawalDetails( withdrawn_amount, fee_asset,
AssetAmount(withdrawn_asset, withdrawn_amount), fee_amount, executed_time,
AssetAmount(fee_asset, fee_amount), item))
executed_time,
item,
),
)
del item del item
return withdrawals return withdrawals
def _get_deposits(self) -> list[DepositDetails]: def _get_deposits(self) -> list[WithdrawalDetails]:
raw_details = self.kucoin_client.get_deposits() raw_details = self.kucoin_client.get_deposits()
deposits = [] deposits = []
@ -226,49 +183,19 @@ class KucoinDepoFetcher(DepoFetcher):
tz=datetime.UTC, tz=datetime.UTC,
) )
deposits.append( deposits.append(DepositDetails(deposit_asset,
DepositDetails( deposit_amount, fee_asset,
AssetAmount(deposit_asset, deposit_amount), fee_amount, executed_time,
AssetAmount(fee_asset, fee_amount), item))
executed_time,
item,
),
)
del item del item
return deposits return deposits
def _get_historic_spot_orders(self) -> Iterator[TradeOrderDetails]:
end_time = datetime.datetime.now(tz=datetime.UTC)
for _weeks_back in range(20):
end_time = end_time - datetime.timedelta(days=7)
timestamp = int(end_time.timestamp() * 1000)
print(timestamp)
raw_details = self.kucoin_client.get_orders(end=timestamp)
yield from (order_from_json(item) for item in raw_details['items'])
del _weeks_back, raw_details
def _get_double_registers(self) -> list[DoubleRegister]:
deposits = self._get_deposits()
withdrawals = self._get_withdrawals()
spot_trades = self._get_historic_spot_orders()
double_registers = []
double_registers += [
DoubleRegister(d.deposit, None, d.executed_time) for d in deposits
]
double_registers += [
DoubleRegister(None, d.withdrawn, d.executed_time) for d in withdrawals
]
double_registers += [
DoubleRegister(d.input, d.output, d.executed_time) for d in spot_trades
]
double_registers.sort(key=lambda x: x.executed_time)
return double_registers
def _get_order_details( def _get_order_details(
self, self,
order_id: str, order_id: str,
input_asset: fin_defs.Asset,
output_asset: fin_defs.Asset,
) -> TradeOrderDetails: ) -> TradeOrderDetails:
"""Determine the order details for the order with the given id. """Determine the order details for the order with the given id.
@ -276,7 +203,29 @@ class KucoinDepoFetcher(DepoFetcher):
order through their systems. order through their systems.
""" """
order_details = self._get_order_with_retries(order_id, num_retries=10) order_details = self._get_order_with_retries(order_id, num_retries=10)
return order_from_json(order_details)
# Convert from kucoin results
if input_asset == fin_defs.USDT:
input_amount_final = Decimal(order_details['dealFunds'])
output_amount_final = Decimal(order_details['dealSize'])
else:
output_amount_final = Decimal(order_details['dealFunds'])
input_amount_final = Decimal(order_details['dealSize'])
return TradeOrderDetails(
input_asset=input_asset,
input_amount=input_amount_final,
output_asset=output_asset,
output_amount=output_amount_final,
fee_asset=parse_asset_from_ticker(order_details['feeCurrency']),
fee_amount=Decimal(order_details['fee']),
executed_time=datetime.datetime.fromtimestamp(
order_details['createdAt'] / 1000,
tz=datetime.UTC,
),
order_id=order_id,
raw_order_details=order_details,
)
def _get_order_with_retries( def _get_order_with_retries(
self, self,

View File

@ -1,5 +1,7 @@
import datetime import datetime
from decimal import Decimal
import fin_defs
import pytest import pytest
import fin_depo import fin_depo
@ -17,7 +19,6 @@ fin_depo.defi_kucoin.logger.setLevel('INFO')
NOW = datetime.datetime.now(tz=datetime.UTC) NOW = datetime.datetime.now(tz=datetime.UTC)
def get_fetcher() -> fin_depo.defi_kucoin.KucoinDepoFetcher: def get_fetcher() -> fin_depo.defi_kucoin.KucoinDepoFetcher:
return fin_depo.defi_kucoin.KucoinDepoFetcher( return fin_depo.defi_kucoin.KucoinDepoFetcher(
secrets.KUCOIN_KEY, secrets.KUCOIN_KEY,
@ -25,7 +26,6 @@ def get_fetcher() -> fin_depo.defi_kucoin.KucoinDepoFetcher:
secrets.KUCOIN_PASS, secrets.KUCOIN_PASS,
) )
@needs_secrets @needs_secrets
def test_get_depo(): def test_get_depo():
"""Can inspect kucoin depository.""" """Can inspect kucoin depository."""
@ -35,28 +35,14 @@ def test_get_depo():
for nested_depo in depo.nested: for nested_depo in depo.nested:
assert isinstance(nested_depo, fin_depo.data.DepoSingle) assert isinstance(nested_depo, fin_depo.data.DepoSingle)
@needs_secrets @needs_secrets
def test_get_withdrawals(): def test_get_withdrawals():
withdrawals = get_fetcher()._get_withdrawals() withdrawals = get_fetcher()._get_withdrawals()
print(withdrawals)
assert len(withdrawals) > 0 assert len(withdrawals) > 0
@needs_secrets @needs_secrets
def test_get_deposits(): def test_get_deposits():
deposits = get_fetcher()._get_deposits() deposits = get_fetcher()._get_deposits()
print(deposits)
assert len(deposits) > 0 assert len(deposits) > 0
@needs_secrets
def test_get_historic_spot_orders():
orders = get_fetcher()._get_historic_spot_orders()
assert next(orders)
@needs_secrets
def test_get_double_registers():
double_registers = get_fetcher()._get_double_registers()
print(double_registers)
assert len(double_registers) > 0
assert False

View File

@ -106,3 +106,4 @@ def test_place_sell_side_order():
assert order_details.fee_amount is not None assert order_details.fee_amount is not None
assert NOW <= order_details.executed_time <= NOW + datetime.timedelta(minutes=10) assert NOW <= order_details.executed_time <= NOW + datetime.timedelta(minutes=10)