def _deserialize_asset_movement( self, raw_data: Dict[str, Any]) -> Optional[AssetMovement]: """Processes a single deposit/withdrawal from binance and deserializes it Can log error/warning and return None if something went wrong at deserialization """ try: if 'insertTime' in raw_data: category = AssetMovementCategory.DEPOSIT time_key = 'insertTime' fee = Fee(ZERO) else: category = AssetMovementCategory.WITHDRAWAL time_key = 'applyTime' fee = Fee(deserialize_asset_amount(raw_data['transactionFee'])) timestamp = deserialize_timestamp_from_binance(raw_data[time_key]) asset = asset_from_binance(raw_data['asset']) tx_id = get_key_if_has_val(raw_data, 'txId') internal_id = get_key_if_has_val(raw_data, 'id') link_str = str(internal_id) if internal_id else str( tx_id) if tx_id else '' return AssetMovement( location=self.location, category=category, address=deserialize_asset_movement_address( raw_data, 'address', asset), transaction_id=tx_id, timestamp=timestamp, asset=asset, amount=deserialize_asset_amount_force_positive( raw_data['amount']), fee_asset=asset, fee=fee, link=link_str, ) except UnknownAsset as e: self.msg_aggregator.add_warning( f'Found {str(self.location)} deposit/withdrawal with unknown asset ' f'{e.asset_name}. Ignoring it.', ) except UnsupportedAsset as e: self.msg_aggregator.add_warning( f'Found {str(self.location)} deposit/withdrawal with unsupported asset ' f'{e.asset_name}. Ignoring it.', ) except (DeserializationError, KeyError) as e: msg = str(e) if isinstance(e, KeyError): msg = f'Missing key entry for {msg}.' self.msg_aggregator.add_error( f'Error processing a {str(self.location)} deposit/withdrawal. Check logs ' f'for details. Ignoring it.', ) log.error( f'Error processing a {str(self.location)} deposit/withdrawal', asset_movement=raw_data, error=msg, ) return None
def _deserialize_asset_movement( self, raw_data: Dict[str, Any]) -> Optional[AssetMovement]: """Processes a single deposit/withdrawal from binance and deserializes it Can log error/warning and return None if something went wrong at deserialization """ try: if 'insertTime' in raw_data: category = AssetMovementCategory.DEPOSIT time_key = 'insertTime' else: category = AssetMovementCategory.WITHDRAWAL time_key = 'applyTime' timestamp = deserialize_timestamp_from_binance(raw_data[time_key]) asset = asset_from_binance(raw_data['asset']) location = Location.BINANCE if self.name == str( Location.BINANCE) else Location.BINANCE_US # noqa: E501 return AssetMovement( location=location, category=category, address=deserialize_asset_movement_address( raw_data, 'address', asset), transaction_id=get_key_if_has_val(raw_data, 'txId'), timestamp=timestamp, asset=asset, amount=deserialize_asset_amount_force_positive( raw_data['amount']), fee_asset=asset, # Binance does not include withdrawal fees neither in the API nor in their UI fee=Fee(ZERO), link=str(raw_data['txId']), ) except UnknownAsset as e: self.msg_aggregator.add_warning( f'Found {self.name} deposit/withdrawal with unknown asset ' f'{e.asset_name}. Ignoring it.', ) except UnsupportedAsset as e: self.msg_aggregator.add_warning( f'Found {self.name} deposit/withdrawal with unsupported asset ' f'{e.asset_name}. Ignoring it.', ) except (DeserializationError, KeyError) as e: msg = str(e) if isinstance(e, KeyError): msg = f'Missing key entry for {msg}.' self.msg_aggregator.add_error( f'Error processing a {self.name} deposit/withdrawal. Check logs ' f'for details. Ignoring it.', ) log.error( f'Error processing a {self.name} deposit_withdrawal', asset_movement=raw_data, error=msg, ) return None
def _deserialize_asset_movement( self, raw_data: Dict[str, Any]) -> Optional[AssetMovement]: """Processes a single deposit/withdrawal from binance and deserializes it Can log error/warning and return None if something went wrong at deserialization """ try: if 'insertTime' in raw_data: category = 'deposit' time_key = 'insertTime' else: category = 'withdrawal' time_key = 'applyTime' timestamp = deserialize_timestamp_from_binance(raw_data[time_key]) asset = asset_from_binance(raw_data['asset']) amount = deserialize_asset_amount(raw_data['amount']) return AssetMovement( exchange=Exchange.BINANCE, category=cast(Literal['deposit', 'withdrawal'], category), timestamp=timestamp, asset=asset, amount=amount, # Binance does not include withdrawal fees neither in the API nor in their UI fee=Fee(ZERO), ) except UnknownAsset as e: self.msg_aggregator.add_warning( f'Found binance deposit/withdrawal with unknown asset ' f'{e.asset_name}. Ignoring it.', ) except UnsupportedAsset as e: self.msg_aggregator.add_warning( f'Found binance deposit/withdrawal with unsupported asset ' f'{e.asset_name}. Ignoring it.', ) except (DeserializationError, KeyError) as e: msg = str(e) if isinstance(e, KeyError): msg = f'Missing key entry for {msg}.' self.msg_aggregator.add_error( 'Error processing a binance deposit/withdrawal. Check logs ' 'for details. Ignoring it.', ) log.error( 'Error processing a binance deposit_withdrawal', asset_movement=raw_data, error=msg, ) return None
def trade_from_binance( binance_trade: Dict, binance_symbols_to_pair: Dict[str, BinancePair], ) -> Trade: """Turn a binance trade returned from trade history to our common trade history format From the official binance api docs (01/09/18): https://github.com/binance-exchange/binance-official-api-docs/blob/62ff32d27bb32d9cc74d63d547c286bb3c9707ef/rest-api.md#terminology base asset refers to the asset that is the quantity of a symbol. quote asset refers to the asset that is the price of a symbol. Throws: - UnsupportedAsset due to asset_from_binance - DeserializationError due to unexpected format of dict entries - KeyError due to dict entries missing an expected entry """ amount = deserialize_asset_amount(binance_trade['qty']) rate = deserialize_price(binance_trade['price']) if binance_trade['symbol'] not in binance_symbols_to_pair: raise DeserializationError( f'Error reading a binance trade. Could not find ' f'{binance_trade["symbol"]} in binance_symbols_to_pair', ) binance_pair = binance_symbols_to_pair[binance_trade['symbol']] timestamp = deserialize_timestamp_from_binance(binance_trade['time']) base_asset = asset_from_binance(binance_pair.binance_base_asset) quote_asset = asset_from_binance(binance_pair.binance_quote_asset) if binance_trade['isBuyer']: order_type = TradeType.BUY # e.g. in RDNETH we buy RDN by paying ETH else: order_type = TradeType.SELL fee_currency = asset_from_binance(binance_trade['commissionAsset']) fee = deserialize_fee(binance_trade['commission']) log.debug( 'Processing binance Trade', sensitive_log=True, amount=amount, rate=rate, timestamp=timestamp, pair=binance_trade['symbol'], base_asset=base_asset, quote=quote_asset, order_type=order_type, commision_asset=binance_trade['commissionAsset'], fee=fee, ) return Trade( timestamp=timestamp, location=Location.BINANCE, pair=trade_pair_from_assets(base_asset, quote_asset), trade_type=order_type, amount=amount, rate=rate, fee=fee, fee_currency=fee_currency, link=str(binance_trade['id']), )