From ea4b464cddc8a9776d89882ba89edfee26d41f53 Mon Sep 17 00:00:00 2001 From: topcoderasdf <107234295+topcoderasdf@users.noreply.github.com> Date: Sat, 5 Nov 2022 01:47:11 -0700 Subject: [PATCH 01/12] Create kucoin_futures.py --- src/dali/plugin/input/rest/kucoin_futures.py | 288 +++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 src/dali/plugin/input/rest/kucoin_futures.py diff --git a/src/dali/plugin/input/rest/kucoin_futures.py b/src/dali/plugin/input/rest/kucoin_futures.py new file mode 100644 index 00000000..ab2ee72b --- /dev/null +++ b/src/dali/plugin/input/rest/kucoin_futures.py @@ -0,0 +1,288 @@ +# Copyright 2022 topcoderasdf +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +import time +from datetime import datetime +from decimal import Decimal +from typing import Any, Dict, List, Optional + +from ccxt import Exchange, RateLimitExceeded, kucoinfutures +from dateutil import tz + +from dali.abstract_ccxt_input_plugin import AbstractCcxtInputPlugin +from dali.ccxt_pagination import AbstractPaginationDetailSet +from dali.configuration import Keyword +from dali.in_transaction import InTransaction +from dali.intra_transaction import IntraTransaction +from dali.out_transaction import OutTransaction + +_AMOUNT: str = "amount" +_CURRENCY: str = "currency" +_DATA: str = "data" +_DATA_LIST: str = "dataList" +_DEPOSIT: str = "Deposit" +_END_AT: str = "endAt" +_HAS_MORE: str = "hasMore" +_OFFSET: str = "offset" +_REALIZED_PNL: str = "RealizedPNL" +_START_AT: str = "startAt" +_TIME: str = "time" +_TRANSFER_IN: str = "TransferIn" +_TRANSFER_OUT: str = "TransferOut" +_TS_INCREMENT: int = 86400000 +_TYPE: str = "type" +_WITHDRAWAL: str = "Withdrawal" + +class InputPlugin(AbstractCcxtInputPlugin): + + __EXCHANGE_NAME: str = "kucoin_futures" + __PLUGIN_NAME: str = "kucoin_futures" + __DEFAULT_THREAD_COUNT: int = 1 + + def __init__( + self, account_holder: str, api_key: str, api_secret: str, api_passphrase: str, native_fiat: Optional[str] = None, thread_count: Optional[int] = None + ) -> None: + self.__api_key = api_key + self.__api_secret = api_secret + self.__api_passphrase = api_passphrase + + super().__init__(account_holder, datetime(2019, 2, 17, 0, 0, 0, 0), native_fiat, thread_count) + + def _initialize_client(self) -> kucoinfutures: + return kucoinfutures( + { + "apiKey": self.__api_key, + "secret": self.__api_secret, + "password": self.__api_passphrase, + "enableRateLimit": True, + } + ) + + def exchange_name(self) -> str: + return self.__EXCHANGE_NAME + + def plugin_name(self) -> str: + return self.__PLUGIN_NAME + + @property + def _client(self) -> kucoinfutures: + super_client: Exchange = super()._client + if not isinstance(super_client, kucoinfutures): + raise TypeError("super_client is not of type kucoinfutures") + + return super_client + + # using kucoin transaction history api instead. (implicit api) + def _get_process_deposits_pagination_detail_set(self) -> Optional[AbstractPaginationDetailSet]: + return None + + def _get_process_withdrawals_pagination_detail_set(self) -> Optional[AbstractPaginationDetailSet]: + return None + + def _get_process_trades_pagination_detail_set(self) -> Optional[AbstractPaginationDetailSet]: + return None + + def _process_gains( + self, + in_transactions: List[InTransaction], + out_transactions: List[OutTransaction], + ) -> None: + pass + + def _fetch_data( + self, + start_at: int, + end_at: int, + ) -> List[Dict[str, Any]]: + + offset: int = 1 + retries: int = 0 + has_more: bool = False + + ledger_transactions: Dict[str, Any] = {} + items: List[Dict[str, Any]] = [] + + while (start_at <= end_at) and retries < 4: + try: + ledger_transactions = self._client.futuresPrivateGetTransactionHistory({_START_AT: start_at, _END_AT: start_at + _TS_INCREMENT}) + data_list = ledger_transactions[_DATA][_DATA_LIST] + has_more = ledger_transactions[_DATA][_HAS_MORE] + + for item in data_list: + items.append(item) + offset = item[_OFFSET] + + # https://github.com/ccxt/ccxt/issues/10273 + # enableRateLimit is not working for kucoin + time.sleep(0.15) + retries = 0 + + while has_more and (retries < 4): + try: + ledger_transactions = self._client.futuresPrivateGetTransactionHistory( + {_START_AT: start_at, _END_AT: start_at + _TS_INCREMENT, _OFFSET: offset} + ) + data_list = ledger_transactions[_DATA][_DATA_LIST] + has_more = ledger_transactions[_DATA][_HAS_MORE] + + for item in data_list: + items.append(item) + offset = item[_OFFSET] + + time.sleep(0.15) + + except RateLimitExceeded: + self._client.sleep(13000) + retries += 1 + + if retries >= 4: + raise Exception("Failed to fetch ledger transactions after 4 retries") + + start_at += _TS_INCREMENT + offset = 1 + has_more = False + retries = 0 + + except RateLimitExceeded: + self._client.sleep(13000) + retries += 1 + + except Exception as exception: + raise exception + + if retries >= 4: + raise Exception("Failed to fetch ledger transactions after 4 retries") + + return items + + def _process_data( + self, + items: List[Dict[str, Any]], + in_transactions: List[InTransaction], + out_transactions: List[OutTransaction], + # intra_transactions: List[IntraTransaction], + ) -> None: + for item in items: + timestamp_value: int = item[_TIME] + timestamp: str = datetime.fromtimestamp(float(timestamp_value) / 1000.0, tz.tzutc()).strftime("%Y-%m-%d %H:%M:%S.%f%z") + transaction_type: str = item[_TYPE] + amount: str = str(item[_AMOUNT]) + currency: str = item[_CURRENCY] + offset: int = item[_OFFSET] + + # internal tranfer between kucoin and kucoin futures. Ignore + if transaction_type in {_TRANSFER_IN, _TRANSFER_OUT}: + continue + + # To do: Currently Kucoin futures allows BTC and USDT deposits / withdrawals through blockchain wallets + if transaction_type in {_DEPOSIT, _WITHDRAWAL}: + pass + + elif transaction_type == _REALIZED_PNL: + amount_value = Decimal(amount) + + # no internal txn id provided by kucoin futures + # unique id manually generated + unique_id = f"realized_pnl:{self.exchange_name}:{self.account_holder}:{timestamp}:{offset}" + + if amount_value > 0: + # Gain + # Example json + # { + # "time": 1644444400000, + # "type": "RealisedPNL", + # "amount": 66.66666666, + # "fee": 0.0, + # "accountEquity": 12345.67890123, + # "status": "Completed", + # "remark": "ETHUSDTM", + # "offset": 123456, + # "currency": "USDT" + # } + + # To do: need to replace tranaction type from GIFT to GAIN + # GAIN currently not implemented in rp2 + in_transactions.append( + InTransaction( + plugin=self.plugin_name(), + unique_id=unique_id, + raw_data=json.dumps(item), + timestamp=timestamp, + asset=currency, + exchange=self.exchange_name(), + holder=self.account_holder, + transaction_type=Keyword.GIFT.name, + spot_price=Keyword.UNKNOWN.value, + crypto_in=str(amount_value), + crypto_fee=None, + fiat_in_no_fee=None, + fiat_in_with_fee=None, + fiat_fee=None, + notes=None, + ) + ) + + else: + # Loss + # Example json + # { + # "time": 1644444400000, + # "type": "RealisedPNL", + # "amount": -66.66666666, + # "fee": 0.0, + # "accountEquity": 12345.67890123, + # "status": "Completed", + # "remark": "ETHUSDTM", + # "offset": 123456, + # "currency": "USDT" + # } + + # To do: need to replace tranaction type from FEE to LOSS + # LOSS currently not implemented in rp2 + out_transactions.append( + OutTransaction( + plugin=self.plugin_name(), + unique_id=unique_id, + raw_data=json.dumps(item), + timestamp=timestamp, + asset=currency, + exchange=self.exchange_name(), + holder=self.account_holder, + transaction_type=Keyword.FEE.value, + spot_price=Keyword.UNKNOWN.value, + crypto_out_no_fee="0", + crypto_fee=str(-amount_value), + crypto_out_with_fee=str(-amount_value), + fiat_out_no_fee=None, + fiat_fee=None, + notes=None, + ) + ) + + def _process_implicit_api( + self, + in_transactions: List[InTransaction], + out_transactions: List[OutTransaction], + intra_transactions: List[IntraTransaction], + ) -> None: + in_transactions.clear() + out_transactions.clear() + intra_transactions.clear() + + end_at: int = int(time.time() * 1000) + start_at: int = self._start_time_ms + + items: List[Dict[str, Any]] = self._fetch_data(start_at, end_at) + self._process_data(items, in_transactions, out_transactions) From 5580d56f04301e83d615146465b7498d691e052f Mon Sep 17 00:00:00 2001 From: topcoderasdf <107234295+topcoderasdf@users.noreply.github.com> Date: Sat, 5 Nov 2022 01:48:49 -0700 Subject: [PATCH 02/12] Update ccxt.pyi added kucoinfutures stubs --- src/stubs/ccxt.pyi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/stubs/ccxt.pyi b/src/stubs/ccxt.pyi index b89ef913..2525327b 100755 --- a/src/stubs/ccxt.pyi +++ b/src/stubs/ccxt.pyi @@ -32,6 +32,7 @@ class Exchange: def fetch_withdrawals( # type: ignore self, code: Optional[str] = ..., since: Optional[int] = ..., limit: Optional[int] = ..., params: Optional[Dict[str, Union[int, str, None]]] = ... ) -> Any: ... + def sleep(self, ms: int) -> None: ... class binance(Exchange): def __init__(self, config: Dict[str, Union[str, bool]]) -> None: ... @@ -64,6 +65,11 @@ class kraken(Exchange): def __init__(self, config: Dict[str, Union[str, bool]]) -> None: ... options: Dict[str, str] +class kucoinfutures(Exchange): + def __init__(self, config: Dict[str, Union[str, bool]]) -> None: ... + options: Dict[str, str] + def futuresPrivateGetTransactionHistory(self, params: Dict[str, int] = ...) -> Any: ... # type: ignore + class liquid(Exchange): def __init__(self, config: Dict[str, Union[str, bool]]) -> None: ... options: Dict[str, str] From 11fd3d21ad63860af5fcec1abc037bf19f5cb34e Mon Sep 17 00:00:00 2001 From: topcoderasdf <107234295+topcoderasdf@users.noreply.github.com> Date: Sat, 5 Nov 2022 01:49:39 -0700 Subject: [PATCH 03/12] Update mypy.ini added kucoin_futures section --- mypy.ini | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mypy.ini b/mypy.ini index 6ba23cd8..26ee053d 100644 --- a/mypy.ini +++ b/mypy.ini @@ -106,6 +106,11 @@ disallow_any_decorated = False disallow_any_explicit = False disallow_any_expr = False +[mypy-dali.plugin.input.rest.kucoin_futures] +disallow_any_decorated = False +disallow_any_explicit = False +disallow_any_expr = False + [mypy-dali.transaction_resolver] disallow_any_unimported = False disallow_any_expr = False From b0c94dc57bbf90a3edf634c78b2ab5f07fe06015 Mon Sep 17 00:00:00 2001 From: topcoderasdf <107234295+topcoderasdf@users.noreply.github.com> Date: Sat, 5 Nov 2022 02:02:31 -0700 Subject: [PATCH 04/12] Update kucoin_futures.py fixing typo bug --- src/dali/plugin/input/rest/kucoin_futures.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dali/plugin/input/rest/kucoin_futures.py b/src/dali/plugin/input/rest/kucoin_futures.py index ab2ee72b..3345fe92 100644 --- a/src/dali/plugin/input/rest/kucoin_futures.py +++ b/src/dali/plugin/input/rest/kucoin_futures.py @@ -36,7 +36,7 @@ _END_AT: str = "endAt" _HAS_MORE: str = "hasMore" _OFFSET: str = "offset" -_REALIZED_PNL: str = "RealizedPNL" +_REALISED_PNL: str = "RealisedPNL" _START_AT: str = "startAt" _TIME: str = "time" _TRANSFER_IN: str = "TransferIn" From 8e6befdfc491d84c274a304ed1979c4a222d42bc Mon Sep 17 00:00:00 2001 From: topcoderasdf <107234295+topcoderasdf@users.noreply.github.com> Date: Sat, 5 Nov 2022 02:14:11 -0700 Subject: [PATCH 05/12] Update kucoin_futures.py fixing typo bug --- src/dali/plugin/input/rest/kucoin_futures.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dali/plugin/input/rest/kucoin_futures.py b/src/dali/plugin/input/rest/kucoin_futures.py index 3345fe92..d13f0560 100644 --- a/src/dali/plugin/input/rest/kucoin_futures.py +++ b/src/dali/plugin/input/rest/kucoin_futures.py @@ -190,7 +190,7 @@ def _process_data( if transaction_type in {_DEPOSIT, _WITHDRAWAL}: pass - elif transaction_type == _REALIZED_PNL: + elif transaction_type == _REALISED_PNL: amount_value = Decimal(amount) # no internal txn id provided by kucoin futures From 9996d7e6a79e63304234ff4060f57f9208942753 Mon Sep 17 00:00:00 2001 From: topcoderasdf <107234295+topcoderasdf@users.noreply.github.com> Date: Sat, 5 Nov 2022 11:28:42 -0700 Subject: [PATCH 06/12] Update kucoin_futures.py change transaction types GIFT -> INCOME, and FEE -> SELL --- src/dali/plugin/input/rest/kucoin_futures.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/dali/plugin/input/rest/kucoin_futures.py b/src/dali/plugin/input/rest/kucoin_futures.py index d13f0560..5c94d245 100644 --- a/src/dali/plugin/input/rest/kucoin_futures.py +++ b/src/dali/plugin/input/rest/kucoin_futures.py @@ -212,7 +212,7 @@ def _process_data( # "currency": "USDT" # } - # To do: need to replace tranaction type from GIFT to GAIN + # To do: need to replace transaction type from INCOME to GAIN # GAIN currently not implemented in rp2 in_transactions.append( InTransaction( @@ -223,14 +223,14 @@ def _process_data( asset=currency, exchange=self.exchange_name(), holder=self.account_holder, - transaction_type=Keyword.GIFT.name, + transaction_type=Keyword.INCOME.value, spot_price=Keyword.UNKNOWN.value, crypto_in=str(amount_value), crypto_fee=None, fiat_in_no_fee=None, fiat_in_with_fee=None, fiat_fee=None, - notes=None, + notes="Futures gain" ) ) @@ -249,7 +249,7 @@ def _process_data( # "currency": "USDT" # } - # To do: need to replace tranaction type from FEE to LOSS + # To do: need to replace transaction type from SELL to LOSS # LOSS currently not implemented in rp2 out_transactions.append( OutTransaction( @@ -260,14 +260,14 @@ def _process_data( asset=currency, exchange=self.exchange_name(), holder=self.account_holder, - transaction_type=Keyword.FEE.value, - spot_price=Keyword.UNKNOWN.value, - crypto_out_no_fee="0", - crypto_fee=str(-amount_value), + transaction_type=Keyword.SELL.value, + spot_price="0", + crypto_out_no_fee=str(-amount_value), + crypto_fee="0", crypto_out_with_fee=str(-amount_value), fiat_out_no_fee=None, fiat_fee=None, - notes=None, + notes="Futures loss", ) ) From 3e3df3c64256f4816142f085306bd9560fbfa766 Mon Sep 17 00:00:00 2001 From: topcoderasdf <107234295+topcoderasdf@users.noreply.github.com> Date: Sun, 6 Nov 2022 12:25:42 -0800 Subject: [PATCH 07/12] Update kucoin_futures.py code review changes --- src/dali/plugin/input/rest/kucoin_futures.py | 110 +++++++++---------- 1 file changed, 52 insertions(+), 58 deletions(-) diff --git a/src/dali/plugin/input/rest/kucoin_futures.py b/src/dali/plugin/input/rest/kucoin_futures.py index 5c94d245..2e81fbe7 100644 --- a/src/dali/plugin/input/rest/kucoin_futures.py +++ b/src/dali/plugin/input/rest/kucoin_futures.py @@ -12,14 +12,18 @@ # See the License for the specific language governing permissions and # limitations under the License. +# Kucoin Futures REST plugin links: +# REST API: https://docs.kucoin.com/futures/#general +# Authentication: https://docs.kucoin.com/futures/#authentication +# Endpoint: https://api-futures.kucoin.com + import json import time from datetime import datetime from decimal import Decimal from typing import Any, Dict, List, Optional -from ccxt import Exchange, RateLimitExceeded, kucoinfutures -from dateutil import tz +from ccxt import DDoSProtection, Exchange, ExchangeError, ExchangeNotAvailable, NetworkError, RateLimitExceeded, RequestTimeout, kucoinfutures from dali.abstract_ccxt_input_plugin import AbstractCcxtInputPlugin from dali.ccxt_pagination import AbstractPaginationDetailSet @@ -41,7 +45,7 @@ _TIME: str = "time" _TRANSFER_IN: str = "TransferIn" _TRANSFER_OUT: str = "TransferOut" -_TS_INCREMENT: int = 86400000 +_ONE_DAY_IN_MS: int = 86400000 _TYPE: str = "type" _WITHDRAWAL: str = "Withdrawal" @@ -107,63 +111,56 @@ def _fetch_data( end_at: int, ) -> List[Dict[str, Any]]: - offset: int = 1 + offset: Optional[int] = None retries: int = 0 - has_more: bool = False + has_more: bool = True ledger_transactions: Dict[str, Any] = {} items: List[Dict[str, Any]] = [] - while (start_at <= end_at) and retries < 4: - try: - ledger_transactions = self._client.futuresPrivateGetTransactionHistory({_START_AT: start_at, _END_AT: start_at + _TS_INCREMENT}) - data_list = ledger_transactions[_DATA][_DATA_LIST] - has_more = ledger_transactions[_DATA][_HAS_MORE] - - for item in data_list: - items.append(item) - offset = item[_OFFSET] - - # https://github.com/ccxt/ccxt/issues/10273 - # enableRateLimit is not working for kucoin - time.sleep(0.15) - retries = 0 - - while has_more and (retries < 4): - try: + while start_at <= end_at: + while has_more and retries < 4: + try: + if offset is None: + ledger_transactions = self._client.futuresPrivateGetTransactionHistory({_START_AT: start_at, _END_AT: start_at + _ONE_DAY_IN_MS}) + else: ledger_transactions = self._client.futuresPrivateGetTransactionHistory( - {_START_AT: start_at, _END_AT: start_at + _TS_INCREMENT, _OFFSET: offset} + {_START_AT: start_at, _END_AT: start_at + _ONE_DAY_IN_MS, _OFFSET: offset} ) - data_list = ledger_transactions[_DATA][_DATA_LIST] - has_more = ledger_transactions[_DATA][_HAS_MORE] - - for item in data_list: - items.append(item) - offset = item[_OFFSET] - - time.sleep(0.15) - - except RateLimitExceeded: - self._client.sleep(13000) - retries += 1 - - if retries >= 4: - raise Exception("Failed to fetch ledger transactions after 4 retries") - - start_at += _TS_INCREMENT - offset = 1 - has_more = False - retries = 0 + data_list = ledger_transactions[_DATA][_DATA_LIST] + has_more = ledger_transactions[_DATA][_HAS_MORE] + + for item in data_list: + items.append(item) + offset = item[_OFFSET] + + # https://github.com/ccxt/ccxt/issues/10273 + # enableRateLimit is not working for kucoin + self._client.sleep(150) + + except RateLimitExceeded: + # sleep for 13 seconds + self._client.sleep(13000) + retries += 1 + except (DDoSProtection, ExchangeError) as exc: + self.__logger.debug( + "Exception from server, most likely too many requests. Making another attempt after 13 second delay. Exception - %s", exc + ) - except RateLimitExceeded: - self._client.sleep(13000) - retries += 1 + self._client.sleep(13000) + retries += 1 - except Exception as exception: - raise exception + except (ExchangeNotAvailable, NetworkError, RequestTimeout) as exc_na: + retries += 1 + self.__logger.debug("Server not available. Making attempt #%s of 4 after a 13 second delay. Exception - %s", retries, exc_na) + self._client.sleep(13000) - if retries >= 4: - raise Exception("Failed to fetch ledger transactions after 4 retries") + if retries >= 4: + raise Exception("Failed to fetch ledger transactions after 4 retries") + start_at += _ONE_DAY_IN_MS + offset = None + has_more = True + retries = 0 return items @@ -175,8 +172,7 @@ def _process_data( # intra_transactions: List[IntraTransaction], ) -> None: for item in items: - timestamp_value: int = item[_TIME] - timestamp: str = datetime.fromtimestamp(float(timestamp_value) / 1000.0, tz.tzutc()).strftime("%Y-%m-%d %H:%M:%S.%f%z") + timestamp: str = self._rp2_timestamp_from_ms_epoch(str(item[_TIME])) transaction_type: str = item[_TYPE] amount: str = str(item[_AMOUNT]) currency: str = item[_CURRENCY] @@ -186,16 +182,16 @@ def _process_data( if transaction_type in {_TRANSFER_IN, _TRANSFER_OUT}: continue - # To do: Currently Kucoin futures allows BTC and USDT deposits / withdrawals through blockchain wallets + # To do: implement deposit/withdrawal using ccxt fetchDeposits()/fetchWithdrawals() if transaction_type in {_DEPOSIT, _WITHDRAWAL}: - pass + continue - elif transaction_type == _REALISED_PNL: + if transaction_type == _REALISED_PNL: amount_value = Decimal(amount) # no internal txn id provided by kucoin futures # unique id manually generated - unique_id = f"realized_pnl:{self.exchange_name}:{self.account_holder}:{timestamp}:{offset}" + unique_id = f"realized_pnl:{self.exchange_name()}:{self.account_holder}:{timestamp}:{offset}" if amount_value > 0: # Gain @@ -279,8 +275,6 @@ def _process_implicit_api( ) -> None: in_transactions.clear() out_transactions.clear() - intra_transactions.clear() - end_at: int = int(time.time() * 1000) start_at: int = self._start_time_ms From 0ccc15fff03a52d87cf59a57484bcc28780cbf0a Mon Sep 17 00:00:00 2001 From: topcoderasdf <107234295+topcoderasdf@users.noreply.github.com> Date: Sun, 6 Nov 2022 22:37:42 -0800 Subject: [PATCH 08/12] Update kucoin_futures.py code review changes --- src/dali/plugin/input/rest/kucoin_futures.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/dali/plugin/input/rest/kucoin_futures.py b/src/dali/plugin/input/rest/kucoin_futures.py index 2e81fbe7..390800a5 100644 --- a/src/dali/plugin/input/rest/kucoin_futures.py +++ b/src/dali/plugin/input/rest/kucoin_futures.py @@ -273,8 +273,6 @@ def _process_implicit_api( out_transactions: List[OutTransaction], intra_transactions: List[IntraTransaction], ) -> None: - in_transactions.clear() - out_transactions.clear() end_at: int = int(time.time() * 1000) start_at: int = self._start_time_ms From 242e49eb3f427cd9469dd067c78ac656cac2f9d9 Mon Sep 17 00:00:00 2001 From: topcoderasdf <107234295+topcoderasdf@users.noreply.github.com> Date: Sat, 12 Nov 2022 10:38:07 -0800 Subject: [PATCH 09/12] Update kucoin_futures.py code review fixes --- src/dali/plugin/input/rest/kucoin_futures.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/dali/plugin/input/rest/kucoin_futures.py b/src/dali/plugin/input/rest/kucoin_futures.py index 390800a5..5a300626 100644 --- a/src/dali/plugin/input/rest/kucoin_futures.py +++ b/src/dali/plugin/input/rest/kucoin_futures.py @@ -20,10 +20,10 @@ import json import time from datetime import datetime -from decimal import Decimal from typing import Any, Dict, List, Optional from ccxt import DDoSProtection, Exchange, ExchangeError, ExchangeNotAvailable, NetworkError, RateLimitExceeded, RequestTimeout, kucoinfutures +from rp2.rp2_decimal import RP2Decimal from dali.abstract_ccxt_input_plugin import AbstractCcxtInputPlugin from dali.ccxt_pagination import AbstractPaginationDetailSet @@ -39,13 +39,14 @@ _DEPOSIT: str = "Deposit" _END_AT: str = "endAt" _HAS_MORE: str = "hasMore" +_MS_IN_SECOND: int = 1000 _OFFSET: str = "offset" +_ONE_DAY_IN_MS: int = 86400000 _REALISED_PNL: str = "RealisedPNL" _START_AT: str = "startAt" _TIME: str = "time" _TRANSFER_IN: str = "TransferIn" _TRANSFER_OUT: str = "TransferOut" -_ONE_DAY_IN_MS: int = 86400000 _TYPE: str = "type" _WITHDRAWAL: str = "Withdrawal" @@ -187,7 +188,7 @@ def _process_data( continue if transaction_type == _REALISED_PNL: - amount_value = Decimal(amount) + amount_value = RP2Decimal(amount) # no internal txn id provided by kucoin futures # unique id manually generated @@ -273,7 +274,7 @@ def _process_implicit_api( out_transactions: List[OutTransaction], intra_transactions: List[IntraTransaction], ) -> None: - end_at: int = int(time.time() * 1000) + end_at: int = int(time.time() * _MS_IN_SECOND) start_at: int = self._start_time_ms items: List[Dict[str, Any]] = self._fetch_data(start_at, end_at) From 3f0e1fa19349ef4e2a08f2196d3fdd08599aef55 Mon Sep 17 00:00:00 2001 From: topcoderasdf <107234295+topcoderasdf@users.noreply.github.com> Date: Sat, 12 Nov 2022 10:59:37 -0800 Subject: [PATCH 10/12] Update configuration_file.md added kucoin futures section --- docs/configuration_file.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/configuration_file.md b/docs/configuration_file.md index d38c7744..9c1c545a 100644 --- a/docs/configuration_file.md +++ b/docs/configuration_file.md @@ -203,6 +203,25 @@ Notes: for sells, please [open an issue](https://github.com/eprbell/dali-rp2/issues). * The Coincheck REST API only supports BTC trades, withdrawals, and deposits and there are currently no plans to implement it. +### Kucoin Futures Section (REST) +This plugin is REST-based and requires setting up API Keys in your Kucoin Futures account settings. + +**IMPORTANT NOTE**: +* when setting up API key/secret/passphrase, only use read permissions (DaLI does NOT need write permissions); +* store your API key, secret and passphrase safely and NEVER share it with anyone! + +Initialize this plugin section as follows: +
+[dali.plugin.input.rest.kucoin_futures <qualifiers>] +account_holder = <account_holder> +api_key = <api_key> +api_secret = <api_secret> +api_passphrase = <api_passphrase> +thread_count = <thread_count> ++ +Note: the `thread_count` parameter is optional and denotes the number of parallel threads used to by the plugin to connect to the endpoint. Kucoin Futures is rate limited by account/userid, so using `thread_count` of 1 is recommended (https://docs.kucoin.com/futures/#request-rate-limit). + ### Ledger Section (CSV) This plugin is CSV-based and parses CSV files generated by Ledger Live. Initialize it as follows:
From 8c923e7f8030aa7d313aaaf466e0c961a1e0ebe7 Mon Sep 17 00:00:00 2001
From: topcoderasdf <107234295+topcoderasdf@users.noreply.github.com>
Date: Sat, 12 Nov 2022 11:10:16 -0800
Subject: [PATCH 11/12] Update configuration_file.md
---
docs/configuration_file.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/configuration_file.md b/docs/configuration_file.md
index 9c1c545a..e26f3c5c 100644
--- a/docs/configuration_file.md
+++ b/docs/configuration_file.md
@@ -184,7 +184,7 @@ native_fiat = <native_fiat>
Notes:
* `withdrawals_csv_file` can be retrieved by clicking [出金 (withdrawals)] -> [出金 button to the right of the asset] -> [CSVドウンロード (CSV download)]
* `withdrawal_code` is the code of the crypto asset that was withdrawn. The csv does not include any information about what asset was withdrawn.
-* This plugin currently only supports withdrawals. If you need support
+* This plugin currently only supports withdrawals. If you need support
for deposits, please [open an issue](https://github.com/eprbell/dali-rp2/issues).
### Coincheck Supplemental Section (CSV)
@@ -199,7 +199,7 @@ native_fiat = <native_fiat>
Notes:
* `buys_csv_file` can be retrieved by clicking [Marketplace (Buy)] -> (Scroll down to the bottom) -> Click on the [🔻] to the right of [Coin purchase history] -> Select [Export to CSV]
* Transfers are not exportable. They will have to be manually added to [transaction hints](https://github.com/eprbell/dali-rp2/blob/main/docs/configuration_file.md#transaction-hints-section)
-* This plugin currently only supports Marketplace Buys. If you need support
+* This plugin currently only supports Marketplace Buys. If you need support
for sells, please [open an issue](https://github.com/eprbell/dali-rp2/issues).
* The Coincheck REST API only supports BTC trades, withdrawals, and deposits and there are currently no plans to implement it.
From 34f763806be5676af1ae26fd396803a2c4881e29 Mon Sep 17 00:00:00 2001
From: topcoderasdf <107234295+topcoderasdf@users.noreply.github.com>
Date: Sat, 12 Nov 2022 11:18:46 -0800
Subject: [PATCH 12/12] Update kucoin_futures.py
---
src/dali/plugin/input/rest/kucoin_futures.py | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/src/dali/plugin/input/rest/kucoin_futures.py b/src/dali/plugin/input/rest/kucoin_futures.py
index 5a300626..27dde8c4 100644
--- a/src/dali/plugin/input/rest/kucoin_futures.py
+++ b/src/dali/plugin/input/rest/kucoin_futures.py
@@ -22,7 +22,16 @@
from datetime import datetime
from typing import Any, Dict, List, Optional
-from ccxt import DDoSProtection, Exchange, ExchangeError, ExchangeNotAvailable, NetworkError, RateLimitExceeded, RequestTimeout, kucoinfutures
+from ccxt import (
+ DDoSProtection,
+ Exchange,
+ ExchangeError,
+ ExchangeNotAvailable,
+ NetworkError,
+ RateLimitExceeded,
+ RequestTimeout,
+ kucoinfutures,
+)
from rp2.rp2_decimal import RP2Decimal
from dali.abstract_ccxt_input_plugin import AbstractCcxtInputPlugin
@@ -50,6 +59,7 @@
_TYPE: str = "type"
_WITHDRAWAL: str = "Withdrawal"
+
class InputPlugin(AbstractCcxtInputPlugin):
__EXCHANGE_NAME: str = "kucoin_futures"
@@ -170,7 +180,6 @@ def _process_data(
items: List[Dict[str, Any]],
in_transactions: List[InTransaction],
out_transactions: List[OutTransaction],
- # intra_transactions: List[IntraTransaction],
) -> None:
for item in items:
timestamp: str = self._rp2_timestamp_from_ms_epoch(str(item[_TIME]))
@@ -227,7 +236,7 @@ def _process_data(
fiat_in_no_fee=None,
fiat_in_with_fee=None,
fiat_fee=None,
- notes="Futures gain"
+ notes="Futures gain",
)
)