def test_deserialize_trade(): trade1 = deserialize_trade(raw_trade1) assert isinstance(trade1, Trade) assert trade1.timestamp == Timestamp(1516985746) assert trade1.location == Location.EXTERNAL assert trade1.pair == TradePair('ETH_EUR') assert trade1.trade_type == TradeType.BUY assert trade1.amount == FVal('20.51') assert trade1.rate == FVal('134.1') assert trade1.fee == FVal('0.01') assert trade1.fee_currency == A_ETH assert isinstance(trade1.fee_currency, Asset) assert trade1.link == '' assert trade1.notes == '' trade2 = deserialize_trade(raw_trade2) assert isinstance(trade2, Trade) assert trade2.timestamp == Timestamp(1537985746) assert trade2.location == Location.KRAKEN assert trade2.pair == TradePair('ETH_BTC') assert trade2.trade_type == TradeType.SELL assert trade2.amount == FVal('2.80') assert trade2.rate == FVal('0.1234') assert trade2.fee == FVal('0.01') assert trade2.fee_currency == A_ETH assert isinstance(trade2.fee_currency, Asset) assert trade2.link == 'a link can be here' assert trade2.notes == 'notes can be here' another_raw_trade = raw_trade2.copy() another_raw_trade['fee_currency'] = 'UNKNOWN' with pytest.raises(UnknownAsset): deserialize_trade(another_raw_trade)
def assert_cointracking_import_results(rotki: Rotkehlchen): """A utility function to help assert on correctness of importing data from cointracking.info""" trades = rotki.data.db.get_trades() asset_movements = rotki.data.db.get_asset_movements() warnings = rotki.msg_aggregator.consume_warnings() errors = rotki.msg_aggregator.consume_warnings() assert len(errors) == 0 assert len(warnings) == 3 expected_trades = [ Trade( timestamp=Timestamp(1566687660), location=Location.COINBASE, pair=TradePair('ETH_EUR'), trade_type=TradeType.BUY, amount=AssetAmount(FVal('0.05772716')), rate=Price(FVal('190.3783245183029963712055123')), fee=Fee(ZERO), fee_currency=A_ETH, link='', notes='', ), Trade( timestamp=Timestamp(1567418400), location=Location.EXTERNAL, pair=TradePair('BTC_USD'), trade_type=TradeType.BUY, amount=AssetAmount(FVal('0.00100000')), rate=Price(ZERO), fee=Fee(ZERO), fee_currency=A_BTC, link='', notes='Just a small gift from someone', ) ] assert expected_trades == trades expected_movements = [ AssetMovement( location=Location.POLONIEX, category=AssetMovementCategory.DEPOSIT, timestamp=Timestamp(1565848620), asset=A_XMR, amount=AssetAmount(FVal('5')), fee_asset=A_XMR, fee=Fee(ZERO), link='', ), AssetMovement( location=Location.COINBASE, category=AssetMovementCategory.WITHDRAWAL, timestamp=Timestamp(1566726120), asset=A_ETH, amount=AssetAmount(FVal('0.05770427')), fee_asset=A_ETH, fee=Fee(ZERO), link='', ) ] assert expected_movements == asset_movements
def test_deserialize_trade(): trade1 = deserialize_trade(raw_trade1) assert isinstance(trade1, Trade) assert trade1.timestamp == Timestamp(1516985746) assert trade1.location == 'external' assert trade1.pair == TradePair('ETH_EUR') assert trade1.trade_type == TradeType.BUY assert trade1.amount == FVal('20.51') assert trade1.rate == FVal('134.1') assert trade1.fee == FVal('0.01') assert trade1.fee_currency == A_ETH assert trade1.link == '' assert trade1.notes == '' trade2 = deserialize_trade(raw_trade2) assert isinstance(trade2, Trade) assert trade2.timestamp == Timestamp(1537985746) assert trade2.location == 'kraken' assert trade2.pair == TradePair('ETH_BTC') assert trade2.trade_type == TradeType.SELL assert trade2.amount == FVal('2.80') assert trade2.rate == FVal('0.1234') assert trade2.fee == FVal('0.01') assert trade2.fee_currency == A_ETH assert trade2.link == 'a link can be here' assert trade2.notes == 'notes can be here'
def test_query_online_trade_history(mock_bitstamp, start_ts, since_id): """Test `since_id` value will change depending on `start_ts` value. Also tests `db_trades` are sorted by `link` (as int) in ascending mode. """ trades = [ Trade( timestamp=1606995000, location=Location.BITSTAMP, pair=TradePair('EUR_USD'), trade_type=TradeType.SELL, amount=FVal("1.22000000"), rate=FVal("0.81967213"), fee=FVal("0.00610000"), fee_currency=Asset('EUR'), link='5', notes='', ), Trade( timestamp=1606901400, location=Location.BITSTAMP, pair=TradePair('BTC_USD'), trade_type=TradeType.BUY, amount=FVal("0.50000000"), rate=FVal("0.00005000"), fee=FVal("20.00000000"), fee_currency=Asset('USD'), link='2', notes='', ), ] database = MagicMock() database.get_trades.return_value = trades expected_call = call( start_ts=start_ts, end_ts=2, options={ 'since_id': since_id, 'limit': 1000, 'sort': 'asc', 'offset': 0, }, case='trades', ) with patch.object(mock_bitstamp, 'db', new_callable=MagicMock(return_value=database)): with patch.object(mock_bitstamp, '_api_query_paginated') as mock_api_query_paginated: mock_bitstamp.query_online_trade_history( start_ts=Timestamp(start_ts), end_ts=Timestamp(2), ) assert mock_api_query_paginated.call_args == expected_call
def deserialize_trade_pair(pair: str) -> TradePair: """Takes a trade pair string, makes sure it's valid, wraps it in proper type and returns it""" try: pair_get_assets(TradePair(pair)) except UnprocessableTradePair as e: raise DeserializationError(str(e)) except UnknownAsset as e: raise DeserializationError( f'Unknown asset {e.asset_name} found while processing trade pair', ) return TradePair(pair)
def test_deserialize_trade_sell(mock_bitstamp): raw_trade = { 'id': 5, 'type': 2, 'datetime': '2020-12-03 11:30:00', 'eur': '-1.00000000', 'usd': '1.22000000', 'eur_usd': '0.81967213', 'fee': '0.00610000', 'order_id': 3, } expected_trade = Trade( timestamp=1606995000, location=Location.BITSTAMP, pair=TradePair('EUR_USD'), trade_type=TradeType.SELL, amount=FVal('1'), rate=FVal('0.81967213'), fee=FVal('0.00610000'), fee_currency=Asset('USD'), link='5', notes='', ) trade = mock_bitstamp._deserialize_trade(raw_trade) assert trade == expected_trade raw_trade = { 'id': 10, 'type': 2, 'datetime': '2019-06-25 21:41:08.802256', 'btc': '-1.81213214', 'usd': '0', 'btc_eur': '10119.82', 'eur': '18338.45', 'fee': '40.35000', 'order_id': 3, } expected_trade = Trade( timestamp=1561498868, location=Location.BITSTAMP, pair=TradePair('BTC_EUR'), trade_type=TradeType.SELL, amount=FVal('1.81213214'), rate=FVal('10119.82'), fee=FVal('40.35'), fee_currency=Asset('EUR'), link='10', notes='', ) trade = mock_bitstamp._deserialize_trade(raw_trade) assert trade == expected_trade
def get_pair_position(pair: TradePair, position: str) -> Asset: assert position == 'first' or position == 'second' currencies = pair.split('_') if len(currencies) != 2: raise ValueError("Could not split {} pair".format(pair)) currency = currencies[0] if position == 'first' else currencies[1] return cast(Asset, currency)
def choose_pair( self, timestamp: Timestamp, price_query: Callable[[Asset, Asset, Timestamp], FVal], ) -> TradePair: """Choose a random pair to trade from the available pairs at the selected timestamp""" choices = set(list(self.asset_pairs['result'].keys())) found = False while len(choices) != 0: pair = random.choice(tuple(choices)) choices.remove(pair) pair = kraken_to_world_pair(pair) base, quote = pair_get_assets(pair) kbase = WORLD_TO_KRAKEN[base] kquote = WORLD_TO_KRAKEN[quote] if kbase in self.balances_dict or kquote in self.balances_dict: # Before choosing make sure that at the selected timestamp both of # the pair assets exist (had a price) if not assets_exist_at_time(base, quote, timestamp, price_query): continue found = True break if not found: raise ValueError('Could not find a pair to trade with the current funds') return TradePair(f'{base}_{quote}')
def test_deserialize_trade_sell(mock_bitfinex): mock_bitfinex.currency_map = {'UST': 'USDt'} mock_bitfinex.pair_bfx_symbols_map = {'ETHUST': ('ETH', 'UST')} raw_result = [ 399251013, 'tETHUST', 1573485493000, 33963608932, -0.26334268, 187.37, 'LIMIT', None, -1, -0.09868591, 'USD', ] expected_trade = Trade( timestamp=Timestamp(1573485493), location=Location.BITFINEX, pair=TradePair('ETH_USDT'), trade_type=TradeType.SELL, amount=AssetAmount(FVal('0.26334268')), rate=Price(FVal('187.37')), fee=Fee(FVal('0.09868591')), fee_currency=Asset('USD'), link='399251013', notes='', ) trade = mock_bitfinex._deserialize_trade(raw_result=raw_result) assert trade == expected_trade
def choose_pair( self, timestamp: Timestamp, price_query: Callable[[Asset, Asset, Timestamp], FVal], ) -> TradePair: """Choose a random pair to trade from the available pairs at the selected timestamp""" choices = set(list(self._symbols_to_pair.keys())) found = False while len(choices) != 0: pair = random.choice(tuple(choices)) choices.remove(pair) binance_pair = self._symbols_to_pair[pair] bbase = binance_pair.base_asset bquote = binance_pair.quote_asset base = binance_to_world(bbase) quote = binance_to_world(bquote) if bbase in self.balances_dict or bquote in self.balances_dict: if bbase in DISALLOWED_ASSETS or bquote in DISALLOWED_ASSETS: continue # Before choosing make sure that at the selected timestamp both of # the pair assets exist (had a price) if not assets_exist_at_time(base, quote, timestamp, price_query): continue found = True break if not found: raise ValueError( 'Could not find a pair to trade with the current funds') return TradePair(f'{base}_{quote}')
def pair_get_assets(pair: TradePair) -> Tuple[Asset, Asset]: """Returns a tuple with the (base, quote) assets""" assets = pair.split('_') if len(assets) != 2: raise ValueError(f'Could not split {pair} pair') return cast(Asset, assets[0]), cast(Asset, assets[1])
def test_deserialize_trade_buy(mock_bitstamp): raw_trade = { 'id': 2, 'type': 2, 'datetime': '2020-12-02 09:30:00', 'btc': '0.50000000', 'usd': '-10000.00000000', 'btc_usd': '0.00005000', 'fee': '20.00000000', 'order_id': 2, } expected_trade = Trade( timestamp=1606901400, location=Location.BITSTAMP, pair=TradePair('BTC_USD'), trade_type=TradeType.BUY, amount=FVal("0.50000000"), rate=FVal("0.00005000"), fee=FVal("20.00000000"), fee_currency=Asset('USD'), link='2', notes='', ) trade = mock_bitstamp._deserialize_trade(raw_trade) assert trade == expected_trade
def mock_exchange_data_in_db(exchanges, rotki) -> None: db = rotki.data.db for exchange_name in exchanges: db.add_trades([ Trade( timestamp=Timestamp(1), location=deserialize_location(exchange_name), pair=TradePair('BTC_ETH'), trade_type=TradeType.BUY, amount=AssetAmount(FVal(1)), rate=Price(FVal(1)), fee=Fee(FVal('0.1')), fee_currency=A_ETH, link='foo', notes='boo', ) ]) db.update_used_query_range(name=f'{exchange_name}_trades', start_ts=0, end_ts=9999) db.update_used_query_range(name=f'{exchange_name}_margins', start_ts=0, end_ts=9999) db.update_used_query_range(name=f'{exchange_name}_asset_movements', start_ts=0, end_ts=9999) # noqa: E501
def gemini_symbol_to_pair(symbol: str) -> TradePair: """Turns a gemini symbol product into our trade pair format - Can raise UnprocessableTradePair if symbol is in unexpected format - Case raise UnknownAsset if any of the pair assets are not known to Rotki """ if len(symbol) == 6: base_asset = Asset(symbol[:3].upper()) quote_asset = Asset(symbol[3:].upper()) elif len(symbol) == 7: try: base_asset = Asset(symbol[:4].upper()) quote_asset = Asset(symbol[4:].upper()) except UnknownAsset: base_asset = Asset(symbol[:3].upper()) quote_asset = Asset(symbol[3:].upper()) elif len(symbol) == 8: if 'storj' in symbol: base_asset = Asset(symbol[:5].upper()) quote_asset = Asset(symbol[5:].upper()) else: base_asset = Asset(symbol[:4].upper()) quote_asset = Asset(symbol[4:].upper()) else: raise UnprocessableTradePair(symbol) return TradePair(f'{base_asset.identifier}_{quote_asset.identifier}')
def query_online_trade_history( self, start_ts: Timestamp, end_ts: Timestamp, ) -> List[Trade]: raw_data = self.return_trade_history( currency_pair='all', start=start_ts, end=end_ts, ) results_length = 0 for _, v in raw_data.items(): results_length += len(v) log.debug('Poloniex trade history query', results_num=results_length) if results_length >= 10000: raise ValueError( 'Poloniex api has a 10k limit to trade history. Have not implemented' ' a solution for more than 10k trades at the moment', ) our_trades = [] for pair, trades in raw_data.items(): for trade in trades: category = trade.get('category', None) try: if category == 'exchange' or category == 'settlement': our_trades.append( trade_from_poloniex(trade, TradePair(pair))) elif category == 'marginTrade': # We don't take poloniex margin trades into account at the moment continue else: self.msg_aggregator.add_error( f'Error deserializing a poloniex trade. Unknown trade ' f'category {category} found.', ) continue except UnsupportedAsset as e: self.msg_aggregator.add_warning( f'Found poloniex trade with unsupported asset' f' {e.asset_name}. Ignoring it.', ) continue except UnknownAsset as e: self.msg_aggregator.add_warning( f'Found poloniex trade with unknown asset' f' {e.asset_name}. Ignoring it.', ) continue except (UnprocessableTradePair, DeserializationError) as e: self.msg_aggregator.add_error( 'Error deserializing a poloniex trade. Check the logs ' 'and open a bug report.', ) log.error( 'Error deserializing poloniex trade', trade=trade, error=str(e), ) continue return our_trades
def test_deserialize_v1_trade(mock_kucoin): raw_result = { 'id': 'xxxx', 'symbol': 'NANO-ETH', 'dealPrice': '0.015743', 'dealValue': '0.00003441', 'amount': '0.002186', 'fee': '0.00000003', 'side': 'sell', 'createdAt': 1520471876, } expected_trade = Trade( timestamp=Timestamp(1520471876), location=Location.KUCOIN, pair=TradePair('NANO_ETH'), trade_type=TradeType.SELL, amount=AssetAmount(FVal('0.002186')), rate=Price(FVal('0.015743')), fee=Fee(FVal('0.00000003')), fee_currency=Asset('ETH'), link='xxxx', notes='', ) trade = mock_kucoin._deserialize_trade( raw_result=raw_result, case=KucoinCase.OLD_TRADES, ) assert trade == expected_trade
def test_deserialize_trade_sell(mock_bitstamp): raw_trade = { 'id': 5, 'type': 2, 'datetime': '2020-12-03 11:30:00', 'eur': '-1.00000000', 'usd': '1.22000000', 'eur_usd': '0.81967213', 'fee': '0.00610000', 'order_id': 3, } expected_trade = Trade( timestamp=1606995000, location=Location.BITSTAMP, pair=TradePair('EUR_USD'), trade_type=TradeType.SELL, amount=FVal("1.22000000"), rate=FVal("0.81967213"), fee=FVal("0.00610000"), fee_currency=Asset('EUR'), link='5', notes='', ) trade = mock_bitstamp._deserialize_trade(raw_trade) assert trade == expected_trade
def _deserialize_trade(self, raw_result: List[Any]) -> Trade: """Process a trade result from Bitfinex and deserialize it. The base and quote assets are instantiated using the `fee_currency_symbol` (from raw_result[10]) over the pair (from raw_result[1]). Known pairs format: 'tETHUST', 'tETH:UST'. Can raise DeserializationError. Schema reference in: https://docs.bitfinex.com/reference#rest-auth-trades """ amount = deserialize_asset_amount(raw_result[4]) trade_type = TradeType.BUY if amount >= ZERO else TradeType.SELL bfx_pair = self._process_bfx_pair(raw_result[1]) if bfx_pair not in self.pair_bfx_symbols_map: raise DeserializationError( f'Could not deserialize bitfinex trade pair {raw_result[1]}. ' f'Raw trade: {raw_result}', ) bfx_base_asset_symbol, bfx_quote_asset_symbol = self.pair_bfx_symbols_map[ bfx_pair] try: base_asset = asset_from_bitfinex( bitfinex_name=bfx_base_asset_symbol, currency_map=self.currency_map, ) quote_asset = asset_from_bitfinex( bitfinex_name=bfx_quote_asset_symbol, currency_map=self.currency_map, ) fee_asset = asset_from_bitfinex( bitfinex_name=raw_result[10], currency_map=self.currency_map, ) except (UnknownAsset, UnsupportedAsset) as e: asset_tag = 'Unknown' if isinstance( e, UnknownAsset) else 'Unsupported' raise DeserializationError( f'{asset_tag} {e.asset_name} found while processing trade pair due to: {str(e)}', ) from e trade = Trade( timestamp=Timestamp(int(raw_result[2] / 1000)), location=Location.BITFINEX, pair=TradePair( f'{base_asset.identifier}_{quote_asset.identifier}'), trade_type=trade_type, amount=AssetAmount(abs(amount)), rate=deserialize_price(raw_result[5]), fee=Fee(abs(deserialize_fee(raw_result[9]))), fee_currency=fee_asset, link=str(raw_result[0]), notes='', ) return trade
def query_online_trade_history( self, start_ts: Timestamp, end_ts: Timestamp, ) -> List[Trade]: raw_data = self.return_trade_history( start=start_ts, end=end_ts, ) results_length = 0 for _, v in raw_data.items(): results_length += len(v) log.debug('Poloniex trade history query', results_num=results_length) our_trades = [] for pair, trades in raw_data.items(): for trade in trades: category = trade.get('category', None) try: if category in ('exchange', 'settlement'): timestamp = deserialize_timestamp_from_poloniex_date( trade['date']) if timestamp < start_ts or timestamp > end_ts: continue our_trades.append( trade_from_poloniex(trade, TradePair(pair))) elif category == 'marginTrade': # We don't take poloniex margin trades into account at the moment continue else: self.msg_aggregator.add_error( f'Error deserializing a poloniex trade. Unknown trade ' f'category {category} found.', ) continue except UnsupportedAsset as e: self.msg_aggregator.add_warning( f'Found poloniex trade with unsupported asset' f' {e.asset_name}. Ignoring it.', ) continue except UnknownAsset as e: self.msg_aggregator.add_warning( f'Found poloniex trade with unknown asset' f' {e.asset_name}. Ignoring it.', ) continue except (UnprocessableTradePair, DeserializationError) as e: self.msg_aggregator.add_error( 'Error deserializing a poloniex trade. Check the logs ' 'and open a bug report.', ) log.error( 'Error deserializing poloniex trade', trade=trade, error=str(e), ) continue return our_trades
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. """ amount = FVal(binance_trade['qty']) rate = FVal(binance_trade['price']) binance_pair = binance_symbols_to_pair[binance_trade['symbol']] timestamp = binance_trade['time'] base_asset = binance_to_world(binance_pair.base_asset) quote_asset = binance_to_world(binance_pair.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 = binance_trade['commissionAsset'] fee = FVal(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='binance', pair=TradePair(f'{base_asset}_{quote_asset}'), trade_type=order_type, amount=amount, rate=rate, fee=fee, fee_currency=fee_currency, )
def test_invert_pair(): pair = invert_pair('ETH_BTC') assert pair == TradePair('BTC_ETH') with pytest.raises(ValueError): invert_pair('_') with pytest.raises(ValueError): invert_pair('ETH_') with pytest.raises(ValueError): invert_pair('_BTC') with pytest.raises(ValueError): invert_pair('ETH_BTC_USD') with pytest.raises(UnknownAsset): invert_pair('ETH_FDFSFDSFDSF') with pytest.raises(UnknownAsset): invert_pair('FDFSFDSFDSF_BTC') pair = invert_pair('ETH_RDN') assert pair == TradePair('RDN_ETH')
def _split_pair(pair: TradePair) -> Tuple[str, str]: assets = pair.split('_') if len(assets) != 2: # Could not split the pair raise UnprocessableTradePair(pair) if len(assets[0]) == 0 or len(assets[1]) == 0: # no base or no quote asset raise UnprocessableTradePair(pair) return assets[0], assets[1]
def _split_pair(pair: TradePair) -> Tuple[str, str]: assets = pair.split('_') if len(assets) != 2: raise ValueError(f'Could not split {pair} pair') if len(assets[0]) == 0: raise ValueError(f'Splitting {pair} yielded no base asset') if len(assets[1]) == 0: raise ValueError(f'Splitting {pair} yielded no quote asset') return assets[0], assets[1]
def coinbasepro_to_worldpair(product: str) -> TradePair: """Turns a coinbasepro product into our trade pair format - Can raise UnprocessableTradePair if product is in unexpected format - Case raise UnknownAsset if any of the pair assets are not known to Rotki """ parts = product.split('-') if len(parts) != 2: raise UnprocessableTradePair(product) base_asset = Asset(parts[0]) quote_asset = Asset(parts[1]) return TradePair(f'{base_asset.identifier}_{quote_asset.identifier}')
def trade_from_coinbase(raw_trade: Dict[str, Any]) -> Optional[Trade]: """Turns a coinbase transaction into a rotkehlchen Trade. https://developers.coinbase.com/api/v2?python#buys If the coinbase transaction is not a trade related transaction returns None Throws: - UnknownAsset due to Asset instantiation - DeserializationError due to unexpected format of dict entries - KeyError due to dict entires missing an expected entry """ if raw_trade['status'] != 'completed': # We only want to deal with completed trades return None if raw_trade['instant']: raw_time = raw_trade['created_at'] else: raw_time = raw_trade['payout_at'] timestamp = deserialize_timestamp_from_date(raw_time, 'iso8601', 'coinbase') trade_type = deserialize_trade_type(raw_trade['resource']) tx_amount = deserialize_asset_amount(raw_trade['amount']['amount']) tx_asset = asset_from_coinbase(raw_trade['amount']['currency'], time=timestamp) native_amount = deserialize_asset_amount(raw_trade['subtotal']['amount']) native_asset = asset_from_coinbase(raw_trade['subtotal']['currency'], time=timestamp) # in coinbase you are buying/selling tx_asset for native_asset pair = TradePair(f'{tx_asset.identifier}_{native_asset.identifier}') amount = tx_amount # The rate is how much you get/give in quotecurrency if you buy/sell 1 unit of base currency rate = Price(native_amount / tx_amount) fee_amount = deserialize_fee(raw_trade['fee']['amount']) fee_asset = asset_from_coinbase(raw_trade['fee']['currency'], time=timestamp) return Trade( timestamp=timestamp, location=Location.COINBASE, pair=pair, trade_type=trade_type, amount=amount, rate=rate, fee=fee_amount, fee_currency=fee_asset, link=str(raw_trade['id']), )
def deserialize_trade_pair(trade_pair_symbol: str) -> TradePair: """May raise: - UnprocessableTradePair - UnknownAsset - UnsupportedAsset """ try: base_asset_symbol, quote_asset_symbol = trade_pair_symbol.split('-') except ValueError as e: raise UnprocessableTradePair(trade_pair_symbol) from e base_asset = asset_from_kucoin(base_asset_symbol) quote_asset = asset_from_kucoin(quote_asset_symbol) return TradePair(f'{base_asset.identifier}_{quote_asset.identifier}')
def bittrex_pair_to_world(given_pair: str) -> Tuple[Asset, Asset]: """ Turns a pair written in bittrex to way to rotki base/quote asset Throws: - UnsupportedAsset due to asset_from_bittrex() - UnprocessableTradePair if the pair can't be split into its parts """ if not isinstance(given_pair, str): raise DeserializationError( f'Could not deserialize bittrex trade pair. Expected a string ' f'but found {type(given_pair)}', ) pair = TradePair(given_pair.replace('-', '_')) base_asset = asset_from_bittrex(get_pair_position_str(pair, 'first')) quote_asset = asset_from_bittrex(get_pair_position_str(pair, 'second')) return base_asset, quote_asset
def bittrex_pair_to_world(given_pair: str) -> TradePair: """ Turns a pair written in the bittrex way to Rotkehlchen way Throws: - UnsupportedAsset due to asset_from_bittrex() """ pair = TradePair(given_pair.replace('-', '_')) base_currency = asset_from_bittrex(get_pair_position_str(pair, 'first')) quote_currency = asset_from_bittrex(get_pair_position_str(pair, 'second')) # Since in Bittrex the base currency is the cost currency, iow in Bittrex # for BTC_ETH we buy ETH with BTC and sell ETH for BTC, we need to turn it # into the Rotkehlchen way which is following the base/quote approach. pair = trade_pair_from_assets(quote_currency, base_currency) return pair
def test_serialize_deserialize_trade(): trade = Trade( timestamp=Timestamp(1537985746), location=Location.KRAKEN, pair=TradePair('ETH_BTC'), trade_type=TradeType.SELL, amount=FVal('2.80'), rate=FVal('0.1234'), fee=FVal('0.01'), fee_currency=A_ETH, link='a link can be here', notes='notes can be here', ) serialized_trade = rlk_jsondumps(trade._asdict()) assert serialized_trade == rlk_jsondumps(raw_trade2) deserialized_trade = deserialize_trade(raw_trade2) assert deserialized_trade == trade
def bittrex_pair_to_world(given_pair: str) -> TradePair: """ Turns a pair written in the bittrex way to Rotkehlchen way Throws: - UnsupportedAsset due to asset_from_bittrex() - UnprocessableTradePair if the pair can't be split into its parts """ if not isinstance(given_pair, str): raise DeserializationError( f'Could not deserialize bittrex trade pair. Expected a string ' f'but found {type(given_pair)}', ) pair = TradePair(given_pair.replace('-', '_')) # Check that there is no unsupported asset in the trade _ = asset_from_bittrex(get_pair_position_str(pair, 'first')) _ = asset_from_bittrex(get_pair_position_str(pair, 'second')) return pair