Laying groundwork for both tax accounting and for repository history
This commit is contained in:
parent
678390e881
commit
c1ae958458
|
@ -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
|
from fin_defs import Asset, AssetAmount
|
||||||
|
|
||||||
|
|
||||||
@enforce_typing.enforce_types
|
@enforce_typing.enforce_types
|
||||||
|
@ -124,12 +124,9 @@ class TradeOrderDetails:
|
||||||
- `raw_order_details`: For storing arbitrary unstructured data from backend.
|
- `raw_order_details`: For storing arbitrary unstructured data from backend.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
input_asset: Asset
|
input: AssetAmount
|
||||||
input_amount: Decimal
|
output: AssetAmount
|
||||||
output_asset: Asset
|
fee: AssetAmount
|
||||||
output_amount: Decimal
|
|
||||||
fee_asset: Asset
|
|
||||||
fee_amount: Decimal
|
|
||||||
executed_time: datetime.datetime
|
executed_time: datetime.datetime
|
||||||
|
|
||||||
order_id: object
|
order_id: object
|
||||||
|
@ -138,26 +135,22 @@ class TradeOrderDetails:
|
||||||
@enforce_typing.enforce_types
|
@enforce_typing.enforce_types
|
||||||
@dataclasses.dataclass(frozen=True)
|
@dataclasses.dataclass(frozen=True)
|
||||||
class WithdrawalDetails:
|
class WithdrawalDetails:
|
||||||
withdrawn_asset: Asset
|
withdrawn: AssetAmount
|
||||||
withdrawn_amount: Decimal
|
fee: AssetAmount
|
||||||
|
|
||||||
fee_asset: Asset
|
|
||||||
fee_amount: Decimal
|
|
||||||
|
|
||||||
executed_time: datetime.datetime
|
executed_time: datetime.datetime
|
||||||
|
|
||||||
raw_details: object
|
raw_details: object
|
||||||
|
|
||||||
@enforce_typing.enforce_types
|
@enforce_typing.enforce_types
|
||||||
@dataclasses.dataclass(frozen=True)
|
@dataclasses.dataclass(frozen=True)
|
||||||
class DepositDetails:
|
class DepositDetails:
|
||||||
deposit_asset: Asset
|
deposit: AssetAmount
|
||||||
deposit_amount: Decimal
|
fee: AssetAmount
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -3,13 +3,15 @@
|
||||||
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
|
||||||
|
from fin_defs import AssetAmount
|
||||||
import kucoin.client
|
import kucoin.client
|
||||||
|
|
||||||
from .data import (DepoFetcher, DepoGroup, DepoSingle, TradeOrderDetails,
|
from .data import (DepoFetcher, DepoGroup, DepoSingle, TradeOrderDetails,
|
||||||
WithdrawalDetails, DepositDetails)
|
WithdrawalDetails, DepositDetails, DoubleRegister)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -19,6 +21,33 @@ def parse_asset_from_ticker(ticker: str) -> fin_defs.Asset:
|
||||||
return fin_defs.CryptoCurrency('KCS', coingecko_id='kucoin-shares')
|
return fin_defs.CryptoCurrency('KCS', coingecko_id='kucoin-shares')
|
||||||
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.
|
||||||
|
@ -145,7 +174,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'], input_asset, output_asset)
|
return self._get_order_details(response['orderId'])
|
||||||
|
|
||||||
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()
|
||||||
|
@ -161,15 +190,15 @@ class KucoinDepoFetcher(DepoFetcher):
|
||||||
tz=datetime.UTC,
|
tz=datetime.UTC,
|
||||||
)
|
)
|
||||||
|
|
||||||
withdrawals.append(WithdrawalDetails(withdrawn_asset,
|
withdrawals.append(WithdrawalDetails(AssetAmount(withdrawn_asset, withdrawn_amount),
|
||||||
withdrawn_amount, fee_asset,
|
AssetAmount(fee_asset, fee_amount),
|
||||||
fee_amount, executed_time,
|
executed_time,
|
||||||
item))
|
item))
|
||||||
del item
|
del item
|
||||||
|
|
||||||
return withdrawals
|
return withdrawals
|
||||||
|
|
||||||
def _get_deposits(self) -> list[WithdrawalDetails]:
|
def _get_deposits(self) -> list[DepositDetails]:
|
||||||
raw_details = self.kucoin_client.get_deposits()
|
raw_details = self.kucoin_client.get_deposits()
|
||||||
|
|
||||||
deposits = []
|
deposits = []
|
||||||
|
@ -183,19 +212,38 @@ class KucoinDepoFetcher(DepoFetcher):
|
||||||
tz=datetime.UTC,
|
tz=datetime.UTC,
|
||||||
)
|
)
|
||||||
|
|
||||||
deposits.append(DepositDetails(deposit_asset,
|
deposits.append(DepositDetails(AssetAmount(deposit_asset, deposit_amount),
|
||||||
deposit_amount, fee_asset,
|
AssetAmount(fee_asset, fee_amount),
|
||||||
fee_amount, executed_time,
|
executed_time, item))
|
||||||
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.
|
||||||
|
|
||||||
|
@ -203,29 +251,8 @@ 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,
|
||||||
|
|
|
@ -38,11 +38,21 @@ def test_get_depo():
|
||||||
@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
|
||||||
|
|
Loading…
Reference in New Issue
Block a user