def query_online_deposits_withdrawals( self, start_ts: Timestamp, end_ts: Timestamp, ) -> List[AssetMovement]: result = self.query_until_finished( endpoint='Ledgers', keyname='ledger', start_ts=start_ts, end_ts=end_ts, extra_dict=dict(type='deposit'), ) result.extend(self.query_until_finished( endpoint='Ledgers', keyname='ledger', start_ts=start_ts, end_ts=end_ts, extra_dict=dict(type='withdrawal'), )) log.debug('Kraken deposit/withdrawals query result', num_results=len(result)) movements = list() for movement in result: try: asset = asset_from_kraken(movement['asset']) movements.append(AssetMovement( location=Location.KRAKEN, category=deserialize_asset_movement_category(movement['type']), timestamp=deserialize_timestamp_from_kraken(movement['time']), asset=asset, amount=deserialize_asset_amount(movement['amount']), fee_asset=asset, fee=deserialize_fee(movement['fee']), link=str(movement['refid']), )) except UnknownAsset as e: self.msg_aggregator.add_warning( f'Found unknown kraken asset {e.asset_name}. ' f'Ignoring its deposit/withdrawals query.', ) continue except (DeserializationError, KeyError) as e: msg = str(e) if isinstance(e, KeyError): msg = f'Missing key entry for {msg}.' self.msg_aggregator.add_error( 'Failed to deserialize a kraken deposit/withdrawals. ' 'Check logs for details. Ignoring it.', ) log.error( 'Error processing a kraken deposit/withdrawal.', raw_asset_movement=movement, error=msg, ) continue return movements
def test_timestamp_deserialization(): """Test the function that allows to deserialize timestamp from different types""" assert deserialize_timestamp_from_kraken("1458994442.2353") == 1458994442 assert deserialize_timestamp_from_kraken(1458994442.2353) == 1458994442 assert deserialize_timestamp_from_kraken(1458994442) == 1458994442 assert deserialize_timestamp_from_kraken( FVal(1458994442.2353)) == 1458994442 with pytest.raises(DeserializationError): deserialize_timestamp_from_kraken("234a") with pytest.raises(DeserializationError): deserialize_timestamp_from_kraken("")
def trade_from_kraken(kraken_trade: Dict[str, Any]) -> Trade: """Turn a kraken trade returned from kraken trade history to our common trade history format - Can raise UnknownAsset due to kraken_to_world_pair - Can raise UnprocessableTradePair due to kraken_to_world_pair - Can raise DeserializationError due to dict entries not being as expected - Can raise KeyError due to dict entries missing an expected entry """ currency_pair = kraken_to_world_pair(kraken_trade['pair']) quote_currency = get_pair_position_asset(currency_pair, 'second') timestamp = deserialize_timestamp_from_kraken(kraken_trade['time']) amount = deserialize_asset_amount(kraken_trade['vol']) cost = deserialize_price(kraken_trade['cost']) fee = deserialize_fee(kraken_trade['fee']) order_type = deserialize_trade_type(kraken_trade['type']) rate = deserialize_price(kraken_trade['price']) if cost != amount * rate: log.warning( 'cost ({cost}) != amount ({amount}) * rate ({rate}) for kraken trade' ) log.debug( 'Processing kraken Trade', sensitive_log=True, timestamp=timestamp, order_type=order_type, kraken_pair=kraken_trade['pair'], pair=currency_pair, quote_currency=quote_currency, amount=amount, cost=cost, fee=fee, rate=rate, ) return Trade( timestamp=timestamp, location='kraken', pair=currency_pair, trade_type=order_type, amount=amount, rate=rate, fee=fee, fee_currency=quote_currency, )
def trade_from_kraken(kraken_trade: Dict[str, Any]) -> Trade: """Turn a kraken trade returned from kraken trade history to our common trade history format - Can raise UnknownAsset due to kraken_to_world_pair - Can raise UnprocessableTradePair due to kraken_to_world_pair - Can raise DeserializationError due to dict entries not being as expected - Can raise KeyError due to dict entries missing an expected entry """ currency_pair = kraken_to_world_pair(kraken_trade['pair']) quote_currency = get_pair_position_asset(currency_pair, 'second') timestamp = deserialize_timestamp_from_kraken(kraken_trade['time']) amount = deserialize_asset_amount(kraken_trade['vol']) cost = deserialize_price(kraken_trade['cost']) fee = deserialize_fee(kraken_trade['fee']) order_type = deserialize_trade_type(kraken_trade['type']) rate = deserialize_price(kraken_trade['price']) # pylint does not seem to see that Price is essentially FVal if not cost.is_close(amount * rate): # pylint: disable=no-member log.warning( f'cost ({cost}) != amount ({amount}) * rate ({rate}) for kraken trade' ) log.debug( 'Processing kraken Trade', sensitive_log=True, timestamp=timestamp, order_type=order_type, kraken_pair=kraken_trade['pair'], pair=currency_pair, quote_currency=quote_currency, amount=amount, cost=cost, fee=fee, rate=rate, ) # Kraken trades can have the same ordertxid and postxid for different trades .. # Also note postxid is optional and can be missing # The only thing that could differentiate them is timestamps in the milliseconds range # For example here are parts of two different kraken_trade: # {'ordertxid': 'AM4ZOZ-GLEMD-ZICOGR', 'postxid': 'AKH2SE-M7IF5-CFI7AT', # 'pair': 'XXBTZEUR', 'time': FVal(1561161486.2955) # {'ordertxid': 'AM4ZOZ-GLEMD-ZICOGR', 'postxid': 'AKH2SE-M7IF5-CFI7AT', # 'pair': 'XXBTZEUR', 'time': FVal(1561161486.3005) # # In order to counter this for the unique exchange trade link we are going # to use a concatenation of the above exchange_uuid = ( str(kraken_trade['ordertxid']) + str(kraken_trade.get('postxid', '')) + # postxid is optional str(kraken_trade['time'])) return Trade( timestamp=timestamp, location=Location.KRAKEN, pair=currency_pair, trade_type=order_type, amount=amount, rate=rate, fee=fee, fee_currency=quote_currency, link=exchange_uuid, )